32位jdk volatile修饰long和double类型

6 篇文章 0 订阅
  • 32位jdk中long和double有什么问题?

long和double是64位的,在32位的jdk中完成write操作是需要两次操作的(每次执行32位)。也就是long和double的write操作是非原子性的。非原子的操作在多线程环境下会有线程安全问题。
比如A,B两个线程同时的去修改long类型x的值,可能x的高32位是A设置的,低32位是B设置的,导致结果不是程序想要的。

  • 为什么volatile修饰的double,long的write操作是原子性的?

volatile它修饰的变量是内存可见性的。但是这个特性不能保证volatile修饰的long,double类型变量的write操作是原子性的,因为它还是发生了两次写操作。
从内存语义的角度来说,volatile的写-读与锁的释放-获取有相同的内存效果。在jsr-133中加强了 volatile 变量的语义,需要有 acquire 和 release 语义。在原始的规范
中,volatile 变量的访问和非 volatile 变量的访问之间可以自由地重排序。

 Acquire语义: Acquire 逻辑上的操作序列为’操作-向后同步’。Acquire操作要求所有后续内存访问都不得被乱序调换到该操作前执行。Acquire操作经常被用于实现互斥量上锁,
 通常Acquire之后的区域为临界区,向后的方向性同步保证了临界区内的内存访问操作不得提前到Acquire之前进行,但不限制Acquire之前的内存访问操作被乱序推迟到临界区内执行。

 Release语义: Release 逻辑上的操作序列为’向前同步-操作’。Release操作要求所有前导内存访问都不得被乱序调换到该操作后执行。Release操作经常被用于实现互斥量解锁,
 通常Release之前的区域为临界区,向前的方向性同步保证了临街区内的内存访问操作不得推迟到Release之后进行,但不限制Release之后的内存访问操作被乱序提前到临界区内执行。

在jsr-133中对double和long的操作也作了说明:

某些 JavaTM 实现可能发现将对 64 位 long 或 double 值的写操作分成两次相邻的 32 位值写操作更方便。为了效率起见,这种行为是实现可以自行决定的。JavaTM 虚拟 机可以自由地决定是原子性的对待 long 和 double 值的写操作还是一分为二的对 待。 鉴于本内存模型的目的,我们将对非 volatile long 或 double 值的单次写操作视作两 次分开的写操作:每次 32 位。这可能会导致一种情况,某个线程会看到某次写操 作中 64 位的前 32 位,以及另外一次写操作的后 32 位。读写 volatile 的 long 和 double 总是原子的。读写引用也总是原子的,而不管引用的实现采用的是 32 位还 是 64 位。 我们鼓励 VM 的实现者尽可能避免将 64 位值的写操作分开。鼓励编码人员将共享 的 64 位值声明为 volaitle 的或将其程序正确同步以避免可能的并发问题。

 

参考资料:

深入理解java内存模型

http://ifeve.com/wp-content/uploads/2014/03/JSR133%E4%B8%AD%E6%96%87%E7%89%88.pdf

 

转载注明出处:https://blog.csdn.net/LCBUSHIHAHA/article/details/97670189

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值