深入思考jvm虚拟机的线程工作内存到底拷贝了 主内存的 什么?,以及volatile修饰对象和基本类型的区别

前一阵子关于这个问题随便记录了一下就结尾了,其实是自己还是没有想明白,现在明白了,分享一下吧。

在深入理解java虚拟机(第一版) 这本书中说:每个线程工作时,都会把主内存中的数据拷贝到线程自己的工作内存中去。

1 对此我一直有疑问,我们知道,如果new一个HashMap 对象(放入很多元素到里面,让这个HashMap很大,比如20M),它是存在于主内存中的堆里面,如果某个线程访问它时,整个HashMap对象也会被拷贝到线程工作内存中吗?线程工作内存可是栈呀,会有这么大吗? 我觉得拷贝的应该是引用的地址。
2 对此又引申出来,按照 线程工作内存拷贝的不是对象本生而是引用地址,那么会得出一个结论 每次访问时(读和写),都是对堆中的同一个对象进行的操作。那么对于引用类型来说,其实不需要volatile就能实现可见性呀。这又与实际情况相矛盾。

所以我真的迷茫了,线程工作内存到底拷贝的什么, 对象本身还是对象的引用地址?无论哪一个都会有说不通的矛盾。
(对于基本类型来说,因为是真的拷贝了主内存中的值到线程工作内存,所以需要volatile修饰)。

跟公司的大牛也交流了一下这个问题,都没有满意的答案,不能解释上面两点矛盾。

直到我看到了第二版 深入理解java虚拟机后,我才搞明白,有这个疑问的不止我一个人,作者特意在书中 12.3.1的注释二 说明了:有不少读者会对这段描述中的“拷贝副本”提出疑问,比如“假设线程中访问一个10MB的对象,也会把这个10MB的内存复制一份拷贝出来吗?”,事实上并不会如此,这个对象的引用、对象中某个在线程访问到的字段是有可能存在拷贝的,但不会有虚拟机实现成把整个对象拷贝一次。

对此就很明白了,线程的工作内存拷贝了对象的引用、和正在访问的对象中的某个字段(对象中其它没有访问到的字段不拷贝),也能完全解释清楚上面两点矛盾。

到此,还有一个小疑问,那么一般虚拟机来说,栈和堆的空间到底多大呢?后续找到答案了再补充。也欢迎高手赐教!

===================以下是之前写的
一 volatile的作用
1 可见性。volatile修饰的变量,线程访问此变量会从主内存中去读写,而不是线程自己的缓存中。
2 非阻塞。不会阻塞访问线程。
3 不具有原子性。对于原子性操作,volatile修饰的变量可以保证原子性,但是非原子性操作不能保证原子性。例如,volatile修饰一个变量,开启20个线程,每个线程循环10000次i++自加这个变量,最后的结果小于200000。因为读取i后,肯能某个线程刚好修改了i的值。(i++其实是三个操作,读,自加,写入)。

二 volatile修饰数组
volatile HashMap testMap = new HashMap();
1 重新赋值。
上面的 new HashMap() 对象,存在于堆中;testMap 存在于栈中,指向上文的new HashMap()对象。
testMap 被volatile修饰,表示多线程访问时,每次都会从主内存中读取testMap 指向的地址。
所以每次给testMap 重新赋值,是符合线程间可见性原则的。
例如:
HashMap map1 = new HashMap();
HashMap map2 = new HashMap();
如果testMap = map1 ;然后又testMap = map2 ;那么获取testMap中的值,确实是map2 所指向的对象的值。

这个结论,从CopyOnWriteArrayList源码中也可以看出来:
private transient volatile Object[] elements;

2 修改对象中的值。
例如testMap.put(“test”, “testKey”);
这时,testMap符合线程间可见性原则吗?
答案是肯定的,原因是,testMap被volatile修饰后,可以认为任何访问它的线程都没有拷贝副本,而是直接访问,既然是直接访问那么访问的都是同一个对象,所以是线程间可见的。

参考文献1,中的例子写的测试代码很不错。

参考文献:
1.volatile修饰数组,那么数组元素可见吗? https://blog.csdn.net/u014674862/article/details/89168376
https://blog.csdn.net/changqijihua/article/details/97517260
2.Java Volatile(包含对volatile数组和对象的理解) https://blog.csdn.net/u014108122/article/details/38173201
3.正确使用 Volatile 变量 https://www.ibm.com/developerworks/cn/java/j-jtp06197.html

  • 8
    点赞
  • 13
    收藏
    觉得还不错? 一键收藏
  • 2
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论 2
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值