【深入理解java虚拟机v3】代码清单4-9 死锁代码样例

文章目录

简介

目的是介绍Jconsole查看死锁线程的状态

例子

public class ThreadDeadLockTestCase_2 {
    
    

	/**
	 * 线程死锁等待演示
	 */
	static class SynAddRunnalbe implements Runnable {
    
    
		int a, b;

		public SynAddRunnalbe(int a, int b) {
    
    
			this.a = a;
			this.b = b;
		}

		@Override
		public void run() {
    
    
			synchronized (Integer.valueOf(a)) {
    
          //锁定A
				synchronized (Integer.valueOf(b)) {
    
      //锁定B
					System.out.println(a + b);
				}
			}
		}
	}

	public static void main(String[] args) {
    
    
		for (int i = 0; i < 100; i++) {
    
    
			new Thread(new SynAddRunnalbe(1, 2)).start();
			new Thread(new SynAddRunnalbe(2, 1)).start();
		}
	}

}

JDK1.6环境运行,包括jconsole

这段代码开了200个线程去分别计算1+2以及2+1的值,理论上for循环都是可省略的,两个线程也可能会导致死锁,不过那样概率太小,需要尝试运行很多次才能看到死锁的效果。如果运气不是特别差的话,上面带for循环的版本最多运行两三次就会遇到线程死锁,程序无法结束。

造成死锁的根本原因是Integer.valueOf()方法出于减少对象创建次数和节省内存的考虑,会对数值为-128~127之间的Integer对象进行缓存 [2] ,如果valueOf()方法传入的参数在这个范围之内,就直接返回缓存中的对象。

《Java虚拟机规范》中明确要求缓存的默认值,实际值可以调整,具体取决于
java.lang.Integer.Integer-Cache.high参数的设置

也就是说代码中尽管调用了200次Integer.valueOf()方法,但一共只返回了两个不同的Integer对象。假如某个线程的两个synchronized块之间发生了一次线程切换,那就会出现线程A在等待被线程B持有的
Integer.valueOf(1),线程B又在等待被线程A持有的Integer.valueOf(2),结果大家都跑不下去的情况。

出现线程死锁之后,点击JConsole线程面板的“检测到死锁”按钮,将出现一个新的“死锁”页签,如下图所示。
在这里插入图片描述
在这里插入图片描述
上图中很清晰地显示,线程Thread-96在等待一个被线程Thread-67持有的Integer对象,而点击线程Thread-67则显示它也在等待一个被线程Thread-96持有的Integer对象,这样两个线程就互相卡住,除非牺牲其中一个,否则死锁无法释放。

猜你喜欢

转载自blog.csdn.net/m0_45406092/article/details/108763289