关于volatile关键字可见性与原子性的问题

Leslie_May 2018-11-29 11:29:44
最近在看Java多线程的书,学习到volatile的时候对可见性与原子性有很大的疑惑。
第一个例子:volatile修饰init_value
Reader线程从主内存获取init_value的值0,并将其缓存到本地工作内存。
Updater线程将init_value的值在本地工作内存中修改为1,然后立即刷新至主内存中。导致Reader线程在本地工作内存中的init_value失效,需要到主内存中重新读取。
这个例子是volatile保证可见性
第二个例子:volatile变量的自增操作
volatile变量arg初始值为0
线程A读取了arg,阻塞
线程B读取arg,对其++,并写回主存,此时arg=1
根据可见性,线程A工作内存中的arg变量应该会失效
此时线程A需要重新从主存中读取arg=1,然后进行++操作,将结果2写回内存
但为什么这里线程A中的arg值不会重新读取,依然是之前读取的0,导致arg被写两次都是1

如果是这样,那么在第一个例子中init_value也不会重新从主内存中读啊

实在被弄迷糊了,望各位大神赐教
...全文
225 7 打赏 收藏 转发到动态 举报
写回复
用AI写文章
7 条回复
切换为时间正序
请发表友善的回复…
发表回复
orcharddd_real 2020-02-26
  • 打赏
  • 举报
回复
为啥要重新获取一遍呢?不能立马就感知到吗?
qq_39936465 2018-11-30
  • 打赏
  • 举报
回复
因为volatile 的可见性只能对应l原子性, a=1是原子性,而a++实际上是a=a+1 是非原子性的,所以会导致你说的情况,这时候就要引入同步,强制将a++转化为原子性。
Leslie_May 2018-11-30
  • 打赏
  • 举报
回复
引用 5 楼 _jant 的回复:
我写了一个示例Demo 你可以看看 启动2个线程,线程A 获取P后阻塞。 线程B直接执行。 在线程A获取 p,阻塞后,看到p其实是0; 阻塞一会,大概率等待线程B执行完毕。手动获取P的值,也就是刚才提到的这里要再次获取P,才能感知到线程B的改动。 可以看到p的值已经为1.
谢谢,所以是线程A需要再次读取的时候才能感知到变化,线程A已经读取了,阻塞释放掉后是不需要再去读取,所以感知不了主内存中的变化。 谢谢!
_jant 2018-11-30
  • 打赏
  • 举报
回复
我写了一个示例Demo 你可以看看

启动2个线程,线程A 获取P后阻塞。 线程B直接执行。 在线程A获取 p,阻塞后,看到p其实是0;

阻塞一会,大概率等待线程B执行完毕。手动获取P的值,也就是刚才提到的这里要再次获取P,才能感知到线程B的改动。


可以看到p的值已经为1.
_jant 2018-11-30
  • 打赏
  • 举报
回复
引用 3 楼 Leslie_May 的回复:
[quote=引用 2 楼 _jant 的回复:]
volatile只保证可见性 不保证原子性

为什么线程A修改主内存的值后。可见性不起作用呢?就是可见性的话,线程A中的值应该更新啊[/quote]
你的描述:
线程A读取了arg,阻塞
线程B读取arg,对其++,并写回主存,此时arg=1

线程A读取arg的时候,线程B有没有将arg++完毕。

你简单一句描述线程A读取了arg,再阻塞。有啥用呢。
给你画个图。


如果a操作在b操作之前 , 你的描述:线程A读取了arg,阻塞。 那么你的arg其实是0;
如果a操作在b和C之间 , 你的描述:线程A读取了arg,阻塞。 那么你的arg其实也是0;
如果a操作在c之后, 你的描述:线程A读取了arg,阻塞。 那么你的arg就是1;

如果完全按照你说的 你线程A 先读取了arg,再阻塞。
线程B完成arg++。并且写回主存。 你释放掉A的阻塞。A的arg照样是0,因为B虽然修改了arg,但是线程A 在阻塞之前已经读过arg了。
arg已经为0,且已经在你的本地工作内存了。只有当你线程A再次去读arg 你才能感知到线程B所带来的变化。 再次读的时候发现arg本地工作内存被清了,这时候会直接去主存取arg的值加载回本地工作内存。这样解释你懂吗?
Leslie_May 2018-11-30
  • 打赏
  • 举报
回复
引用 2 楼 _jant 的回复:
volatile只保证可见性 不保证原子性
为什么线程A修改主内存的值后。可见性不起作用呢?就是可见性的话,线程A中的值应该更新啊
_jant 2018-11-30
  • 打赏
  • 举报
回复
volatile只保证可见性 不保证原子性

62,614

社区成员

发帖
与我相关
我的任务
社区描述
Java 2 Standard Edition
社区管理员
  • Java SE
加入社区
  • 近7日
  • 近30日
  • 至今
社区公告
暂无公告

试试用AI创作助手写篇文章吧