![](https://i-blog.csdnimg.cn/blog_migrate/a41954a27d6ad96fa2c2cf816e677448.gif)
![](https://i-blog.csdnimg.cn/blog_migrate/6a9c071a08f1dae2d3e1c512000eef41.gif)
![](https://i-blog.csdnimg.cn/blog_migrate/37c8bf68cdc3cc81759c34160776bc53.gif)
![](https://i-blog.csdnimg.cn/blog_migrate/37c8bf68cdc3cc81759c34160776bc53.gif)
![](https://i-blog.csdnimg.cn/blog_migrate/37c8bf68cdc3cc81759c34160776bc53.gif)
![](https://i-blog.csdnimg.cn/blog_migrate/6a9c071a08f1dae2d3e1c512000eef41.gif)
![](https://i-blog.csdnimg.cn/blog_migrate/6a9c071a08f1dae2d3e1c512000eef41.gif)
![](https://i-blog.csdnimg.cn/blog_migrate/717446ca04a6125dc5b6b54e0fa14ab4.gif)
![](https://i-blog.csdnimg.cn/blog_migrate/717446ca04a6125dc5b6b54e0fa14ab4.gif)
![](https://i-blog.csdnimg.cn/blog_migrate/6a9c071a08f1dae2d3e1c512000eef41.gif)
![](https://i-blog.csdnimg.cn/blog_migrate/6a9c071a08f1dae2d3e1c512000eef41.gif)
![](https://i-blog.csdnimg.cn/blog_migrate/6a9c071a08f1dae2d3e1c512000eef41.gif)
![](https://i-blog.csdnimg.cn/blog_migrate/717446ca04a6125dc5b6b54e0fa14ab4.gif)
![](https://i-blog.csdnimg.cn/blog_migrate/6a9c071a08f1dae2d3e1c512000eef41.gif)
![](https://i-blog.csdnimg.cn/blog_migrate/37c8bf68cdc3cc81759c34160776bc53.gif)
![](https://i-blog.csdnimg.cn/blog_migrate/6a9c071a08f1dae2d3e1c512000eef41.gif)
![](https://i-blog.csdnimg.cn/blog_migrate/717446ca04a6125dc5b6b54e0fa14ab4.gif)
![](https://i-blog.csdnimg.cn/blog_migrate/0196c3df5ea9e936f21e9932cca91014.gif)
输出“enter thread”后死循环。
这个小程序不会终止。其主线程会陷入死循环,那个单独的线程会永远等待。为方便起见,称主线程为M,单独的线程为N。代码的执行过程大体如下:
1. M看到类Init, 获取Init.class上的锁,判断初始化是否正在进行,或着已完成。
2. 此时初始化既未进行,也未完成,于是M设一个标志表示初始化正在进行,然后释放Init.class上的锁
3. M开始初始化类Init, 完成对Init.done的初始化
4. M进入static块,启动N, 进入while循环
5. N开始运行,打印出"enter thread",
6. N看到Init.done, 这是N第一次看到类Init, 所以像M一样,试图初始化Init。
7. 与步骤1类似,N 成功获取Init.class上的锁
8. N发现M所设的初始化正在进行的标志,N就释放Init.class的锁,并进入等待状态。
9. 由于N在等待,Init.done一直为false,M就一直在while中循环,不能退出static块.
10. 由于M对Init的初始化不能完成,所以N不能得到M的通知而退出等待。
可见,这是一个M和N的死锁问题。
一般而言,只要N引用类本身或类的成员,包括任何method或field,N都会先去初始化这个类从而陷入死锁。
但是有例外,例如如果N引用的是一个常变量(constant variable),N 就不会去初始化这个类,例如如果Init有以下成员, 引用它就可以。
final boolean ok = false;
还有一个例外,以下语句出现在run()中也不会引发Init的初始化.
Init C = null;