栏目分类:
子分类:
返回
名师互学网用户登录
快速导航关闭
当前搜索
当前分类
子分类
实用工具
热门搜索
名师互学网 > IT > 面试经验 > 面试问答

为什么Java 5+中的volatile不能确保另一个线程的可见性?

面试问答 更新时间: 发布时间: IT归档 最新发布 模块sitemap 名妆网 法律咨询 聚返吧 英语巴士网 伯小乐 网商动力

为什么Java 5+中的volatile不能确保另一个线程的可见性?

更新:

对于有兴趣的人,此错误已得到解决,并已在Java 7u6 build b14中修复。您可以在此处查看错误报告/修复程序

  • 报告
  • 变更集
  • 错误清单

原始答案

在考虑内存可见性/顺序时,您需要考虑其事前发生的关系。的重要前提

b != 0
a == 1
。如果是,
a != 1
则b可以为0或1。

一旦看到

a == 1
线程,便保证该线程看到
b == 1

在OP示例中,在Java 5之后,一旦

while(a == 0)
突破b保证为1

编辑:

我多次运行模拟,但没有看到您的输出。

您在什么操作系统,Java版本和CPU下进行测试?

我在Windows 7,Java 1.6_24上(尝试_31)

编辑2:

对OP和Walter Laan表示敬意-对我来说,只有在我从64位Java切换到32位Java时,才发生这种情况,但不一定排除在64位Windows 7中。

编辑3:

指派给

tt
,或者说静态化
b
似乎有很大的影响(以证明删除了
int tt = b;
,它应该一直有效。

它出现的负载

b
tt
将本地存储的字段,它然后将在如果coniditonal被使用(参考到该值不
tt
)。因此,如果
b ==0
为true,则可能意味着to的本地存储为
tt
0(这是将1分配给local的竞赛
tt
)。这似乎仅对于带有客户端集的32位Java
1.6和7是正确的。

我比较了两个输出组件,直接的区别就在这里。(请记住,这些都是片段)。

这样印“错误”

 0x021dd753: test   %eax,0x180100      ;   {poll}  0x021dd759: cmp    $0x0,%ecx  0x021dd75c: je     0x021dd748         ;*ifeq       ; - Test$1::run@7 (line 13)  0x021dd75e: cmp    $0x0,%edx  0x021dd761: jne    0x021dd788         ;*ifne       ; - Test$1::run@13 (line 17)  0x021dd767: nop      0x021dd768: jmp    0x021dd7b8         ;   {no_reloc}  0x021dd76d: xchg   %ax,%ax  0x021dd770: jmp    0x021dd7d2         ; implicit exception: dispatches to 0x021dd7c2  0x021dd775: nop ;*getstatic out       ; - Test$1::run@16 (line 18)  0x021dd776: cmp    (%ecx),%eax        ; implicit exception: dispatches to 0x021dd7dc  0x021dd778: mov    $0x39239500,%edx   ;*invokevirtual println

这没有打印“错误”

0x0226d763: test   %eax,0x180100      ;   {poll}  0x0226d769: cmp    $0x0,%edx  0x0226d76c: je     0x0226d758         ;*ifeq       ; - Test$1::run@7 (line 13)  0x0226d76e: mov    $0x341b77f8,%edx   ;   {oop('Test')}  0x0226d773: mov    0x154(%edx),%edx   ;*getstatic b       ; - Test::access$0@0 (line 3)       ; - Test$1::run@10 (line 17)  0x0226d779: cmp    $0x0,%edx  0x0226d77c: jne    0x0226d7a8         ;*ifne       ; - Test$1::run@13 (line 17)  0x0226d782: nopw   0x0(%eax,%eax,1)  0x0226d788: jmp    0x0226d7ed         ;   {no_reloc}  0x0226d78d: xchg   %ax,%ax  0x0226d790: jmp    0x0226d807         ; implicit exception: dispatches to 0x0226d7f7  0x0226d795: nop ;*getstatic out       ; - Test$1::run@16 (line 18)  0x0226d796: cmp    (%ecx),%eax        ; implicit exception: dispatches to 0x0226d811  0x0226d798: mov    $0x39239500,%edx   ;*invokevirtual println

在此示例中,第一个条目来自打印“错误”的运行,而第二个条目则来自未打印错误的运行。

似乎

b
在测试等于0之前,已正确加载和分配了工作运行。

  0x0226d76e: mov    $0x341b77f8,%edx   ;   {oop('Test')}  0x0226d773: mov    0x154(%edx),%edx   ;*getstatic b       ; - Test::access$0@0 (line 3)       ; - Test$1::run@10 (line 17)  0x0226d779: cmp    $0x0,%edx  0x0226d77c: jne    0x0226d7a8         ;*ifne       ; - Test$1::run@13 (line 17)

当打印“错误”的运行加载了缓存的版本时

%edx

  0x021dd75e: cmp    $0x0,%edx  0x021dd761: jne    0x021dd788         ;*ifne       ; - Test$1::run@13 (line 17)

对于那些对汇编程序有更多经验的人,请权衡:)

编辑4

应该是我的最后一个编辑,因为并发开发人员可以使用它,我在有和没有

int tt = b;
分配的情况下进行
了更多测试。我发现,当我将最大值从100增加到1000时
int tt = b
,包含时似乎有100%的错误率,而排除它时似乎有0%的机会。



转载请注明:文章转载自 www.mshxw.com
本文地址:https://www.mshxw.com/it/514969.html
我们一直用心在做
关于我们 文章归档 网站地图 联系我们

版权所有 (c)2021-2022 MSHXW.COM

ICP备案号:晋ICP备2021003244-6号