关于volatile happens-before保证的代码疑问:是否必然打印France = Paris?
volatile的Happens-Before保证与线程可见性问题
原代码中第二个线程是否必然能看到键值对?
是的,必然能看到。核心原因是主线程调用了t.join():根据Java线程同步规则,线程t的所有操作(包括capitals.put("France", "Paris"))都happens-before于t.join()的返回,而t.join()的返回又happens-before于第二个线程的启动。这就确保了第二个线程执行时,线程t的put操作对它完全可见。这里capitals的volatile修饰是额外保障,但核心可见性由t.join()的同步语义提供。
两种特殊场景的分析
场景1:capitals不声明为volatile,但保留t.join()
依然能保证第二个线程打印France = Paris。t.join()的同步规则已经完全覆盖了可见性需求,volatile在这里不是必需条件。
场景2:用Thread.sleep(1000)替代t.join()(无论capitals是否为volatile)
无法保证第二个线程能看到键值对,理由如下:
Thread.sleep()仅让主线程暂停,没有任何同步语义,不能确保线程t的put操作在第二个线程启动前完成,也无法保证put操作的结果能被第二个线程读到。- 即使sleep时长看似足够,线程调度具有不确定性,线程
t可能未完成put;或者put完成了,但由于CPU缓存一致性问题,第二个线程的本地缓存未同步到最新的map数据。另外,volatile仅保证capitals引用本身的可见性,无法保证map内部结构修改的可见性——除非每次修改后重新赋值capitals(比如capitals = new HashMap<>(capitals)),但原代码并未这么做。
内容的提问来源于stack exchange,提问作者Priyshrm
相关产品推荐
相关产品推荐

