《java并发编程实战》读书笔记一 可见性和重排序现象
2016-04-10 21:45
435 查看
第3.1章节《可见性》里给了一段代码:
根据作者意思,NoVisibility可能会输出42,也有可能输出0,甚至可能导致死循环,不会输出。原因是因为没有使用恰当的同步机制,没能保证主线程写入ready和number的值对读线程是可见的。
作者在书中提到两个概念:可见性和“重排序(reordering)”现象。
具体分析:
首先类加载会初始化ready和number的值分别为false和0,我们认为正常情况下,number被赋值为42,ready赋值为true,结果应该为:输出42,读线程、主线程执行完成,结束。
其实不然,还会有另外三种情况:
1.无限循环,number的值为0:在主线程即main方法中对ready的设置(即ready = true)还没来得及写回主存(静态变量保存在方 法区),ReaderThread 线程就已经读取了ready的值(并保留了副本),然后加载到Java栈中,此时ready 一直为false所以出 现死循环。number的值也可以类似推理,在主线程即main方法中对number的设置(即number= 42)还没来得及写回主存(静态变量保存 在方法区),ReaderThread 线程就已经读取了number的值(并保留了副本),然后加载到Java栈中,此时number一直为0(只是没 有打印出来而已);
2.无限循环,number的值为42:在主线程即main方法中对ready的设置(即ready = true)还没来得及写回主存(静态变量保存在 方法区),ReaderThread 线程就已经读取了ready的值(并保留了副本),然后加载到Java栈中,此时ready 一直为false所以 出现死循环。在主线程即main方法中对number的设置(即number= 42)后(即number的值已经写回了主 存),ReaderThread 线程才开始执行此时读取的number为42(只是没有打印出来而已);
3.输出0:在主线程即main方法中对ready的设置(即ready = true)后(即ready的值已经写回了主存),还没来得及写回主存(静 态变量保存在方法区),ReaderThread 线程就已经读取了number的值(并保留了副本),然后加载到Java栈中,此时number为0;
至于为什么会出现ready = true写回主存后,number = 42还没写回主存。这应该是由于Java虚拟机的一种优化技术叫指令重排序,number = 42不一定会在ready = true前面执行,得看Java虚拟机是怎么优化的。
内容来源:http://bbs.csdn.net/topics/390715765/
publci class NoVisibility{ private static voolean ready; private static int number; private static class ReaderThread extends Thread{ public void run() { while(!ready) Thread.yield(); System.out.println(number); } } public static void main(String[] args) { new ReaderThread().start(); number = 42; ready = true; } }
根据作者意思,NoVisibility可能会输出42,也有可能输出0,甚至可能导致死循环,不会输出。原因是因为没有使用恰当的同步机制,没能保证主线程写入ready和number的值对读线程是可见的。
作者在书中提到两个概念:可见性和“重排序(reordering)”现象。
具体分析:
首先类加载会初始化ready和number的值分别为false和0,我们认为正常情况下,number被赋值为42,ready赋值为true,结果应该为:输出42,读线程、主线程执行完成,结束。
其实不然,还会有另外三种情况:
1.无限循环,number的值为0:在主线程即main方法中对ready的设置(即ready = true)还没来得及写回主存(静态变量保存在方 法区),ReaderThread 线程就已经读取了ready的值(并保留了副本),然后加载到Java栈中,此时ready 一直为false所以出 现死循环。number的值也可以类似推理,在主线程即main方法中对number的设置(即number= 42)还没来得及写回主存(静态变量保存 在方法区),ReaderThread 线程就已经读取了number的值(并保留了副本),然后加载到Java栈中,此时number一直为0(只是没 有打印出来而已);
2.无限循环,number的值为42:在主线程即main方法中对ready的设置(即ready = true)还没来得及写回主存(静态变量保存在 方法区),ReaderThread 线程就已经读取了ready的值(并保留了副本),然后加载到Java栈中,此时ready 一直为false所以 出现死循环。在主线程即main方法中对number的设置(即number= 42)后(即number的值已经写回了主 存),ReaderThread 线程才开始执行此时读取的number为42(只是没有打印出来而已);
3.输出0:在主线程即main方法中对ready的设置(即ready = true)后(即ready的值已经写回了主存),还没来得及写回主存(静 态变量保存在方法区),ReaderThread 线程就已经读取了number的值(并保留了副本),然后加载到Java栈中,此时number为0;
至于为什么会出现ready = true写回主存后,number = 42还没写回主存。这应该是由于Java虚拟机的一种优化技术叫指令重排序,number = 42不一定会在ready = true前面执行,得看Java虚拟机是怎么优化的。
内容来源:http://bbs.csdn.net/topics/390715765/
相关文章推荐
- Eclipse插件开发中各种路径的获取(一)
- Java注解
- 蓝桥杯 -算法训练 区间k大数查询 java算法
- Spring中的设计模式
- java abstract类和interface的区别,精辟!
- java中静态代码块、静态方法、static关键字详解
- java基础(三),字符串
- Java Nio 十二、Java NIO DatagramChannel(数据报通道)
- 20145322 《Java程序设计》第6周学习总结
- 轻量级javaee最后工作流项目总结
- Java的加载资源文件+JavaBean+内省机制
- 20145120 《Java程序设计》第6周学习总结
- struts2环境配置
- Java反射学习总结
- Spring-boot中利用外部配置文件生成数据源
- 在Myeclipse 中导入java web项目出现JRE System Library(unbound)和Server Library(unbound)解决方法
- Java并发编程:Lock
- Java编码规范
- Java各种对象理解(转)
- 20145239 《Java程序设计》第6周学习总结