看不见的锁 -- 对小程序的运行结果的解释
发布日期:2021-09-30 18:32:23 浏览次数:1 分类:技术文章

本文共 1214 字,大约阅读时间需要 4 分钟。

From:  

在以前的文章中,我提到一个有趣的小程序,现在就对它的行为做一解释。为方便起见,将那段代码重抄~如下:

class Init{
        static volatile boolean done = false;
        static {
                new Thread() {
                        public void run() {
                                System.out.println("enter thread");
                                done = true;
                        }
                }.start();
                while(!done);
        }
        public static void main(String[] args) {}
}
这个小程序不会终止。其主线程会陷入死循环,那个单独的线程会永远等待。为方便起见,称主线程为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;
以上所描述的答案和例外都可以在Java的语言规范中找到依据,有兴趣的人可以看看
http://java.sun.com/docs/books/jls/third_edition/html/execution.html#12.4
最后,有两个建议给大家:一是不要写这种晦涩的代码,一般而言,水平最高的代码是那种简洁易懂,使~人一望而知的代码,所谓洗尽铅华,归于平淡;二是万一遇到这样的代码,想彻底弄懂它,可以读一读Java语言规范和虚拟机规范,这两本书可是我们的倚天、屠龙。

转载地址:https://blog.csdn.net/iteye_10746/article/details/81418469 如侵犯您的版权,请留言回复原文章的地址,我们会给您删除此文章,给您带来不便请您谅解!

上一篇:JAVA开发者常去的英文网站
下一篇:书评:Innovation

发表评论

最新留言

感谢大佬
[***.8.128.20]2024年03月24日 18时55分28秒

关于作者

    喝酒易醉,品茶养心,人生如梦,品茶悟道,何以解忧?唯有杜康!
-- 愿君每日到此一游!

推荐文章

java 符号 t_java – 运算符”不能应用于’T’,’T’表示有界泛型类型 2019-04-21
用matlab写出信源熵,计算离散信源的熵matlab实现 2019-04-21
php表单yii2,Yii2创建表单(ActiveForm)方法详解 2019-04-21
php 程序授权机制,授权认证详细说明 2019-04-21
java 命令提示符,如何使用Java打开命令提示符并插入命令? 2019-04-21
IP/tzgm.php,LianjiaSpider/在售数量.ipynb at master · BerSerK/LianjiaSpider · GitHub 2019-04-21
linux移动文件的脚本,使用Linux脚本移动文件 2019-04-21
linux查看系统所有变量,Linux系统各指标命令 2019-04-21
linux打印机守护程序,linux下怎么编写守护程序呢? 2019-04-21
嵌入式linux 设置时间,time_clock控件应用,使用命令date -s 12:00:00手动设置时间后,时间就停住不走了,我在Ubuntu和嵌入式Linux平台都测试到了... 2019-04-21
linux 8086下编译,Ubuntu18.04/Linux下安装DosBox进行8086汇编 2019-04-21
linux监控windows,zabbix监控之linux及windows客户端安装配置 2019-04-21
linux中怎么卸载tree,Liunx系统命令中tree命令详解 2019-04-21
linux 网络音箱 混音6,Linux音频编程(三)混音器介绍 2019-04-21
node与mysql开源_node与mysql的相互使用————node+mysql 2019-04-21
python合并列表重新排序_python – 将两个已排序的列表合并为一个更大的排序列表... 2019-04-21
vbs用mysql语句查询数据库_vbs脚本实现window环境下的mysql数据库的备份及删除早期备份... 2019-04-21
mysql连接nginx_nginx四层负载均衡连接mysql 2019-04-21
mysql截取栏目字符_substring从指定字符串开始截取(图) 2019-04-21
python 函数参数前面两个星号_Python中参数前面一个星号两个星号(*参数,**参数)起什么作用呢?... 2019-04-21