创建新线程是否会导致缓存刷新的副作用?

6
我想知道在Java中创建一个新线程是否会触发缓存刷新。假设我按照以下顺序进行操作:
  1. 一个线程运行并设置变量X。
  2. 该线程创建一个新线程。
  3. 新线程访问X。
我的问题是:在新线程被创建或开始执行时,它是否保证能看到旧线程在步骤1中对X所做的更新?如果旧线程在未来更改X的值,则不能保证新线程将看到这些更改。没关系,我只想知道新线程在启动时是否能看到正确的值,而不需要显式同步。
当我第一次决定研究这个主题时,我认为简单的谷歌搜索会立即揭示答案,但出于某种原因,我找不到任何回答这个问题的结果。

3
如果可以将问题变量设置为“volatile”,为什么要依赖这样模糊的保证(如果它们存在的话)? - user395760
5
@delnan:这里没有什么晦涩难懂的地方。Java 语言规范已经明确规定了这种行为。 - Peter Štibraný
@pst:不确定B与此有何关系。在这种情况下,C保证会看到默认值或者A写入的值,但没有指定是哪一个。(假设没有其他对X的写操作,并且“A写入X”和“C读取X”的动作没有通过其他方式进行同步,例如使用volatile)。 - Peter Štibraný
@pst:一般来说,如果没有适当的同步,你只能对可见的值做出少数保证。其中之一是你只会看到其他线程实际写入的值(包括默认值),而不是一些随机值。虽然这并没有什么帮助,但在原问题的情况下,动作1和3已经得到了适当的同步! - Peter Štibraný
1
@pst:创建线程和等待(加入)线程时都需要同步。 - ninjalj
显示剩余6条评论
1个回答

9

是的,是这样的。

在Java中,有一个“先于发生”(happens-before)关系,它指定了两个动作之间可见的内存效果。如果“A先于发生B”,那么保证动作B将看到由动作A所做的所有更改。

启动线程会在“thread.start()”调用和在新线程上执行的所有代码之间创建“先于发生”关系。因此,可以保证新线程将看到第一个线程上更改变量X的内存效果。

要快速了解“先于发生”关系,请参阅java.util.concurrent包概述中的内存可见性部分。在您的情况下,有趣的部分包括:

  • 线程中的每个动作都先于程序顺序中稍后出现的该线程中的每个动作。
  • 对线程调用start发生在已启动线程的任何动作之前。

如果您感兴趣,以下是更多链接:


一个不错的回答,然而通过阅读这个概要,我不清楚这是否被定义了:线程存在,A,B,变量X未知A写入X;B创建C;C读取X。请注意,C是由B创建的,而不是A--因此,A和C之间没有发生在之前?(请注意,这不是原始问题所问的内容,这个问题确实有答案,只是思考! :-) - user166390
@pst:是的,你说得对。在这种情况下,“A写入X”和“C读取X”操作之间没有先于关系。 - Peter Štibraný
@PeterŠtibraný:你的意思是,“B创建C”和“C读取X”之间确实存在happens-before关系,但“A写入X”与B或C中的任何其他操作之间都不存在。 - ninjalj
作为参考,我检查了链接文档中特定部分有关Thread.start()同步的说明:“同步操作会在动作上引入synchronized-with关系,定义如下:-启动线程的动作与其启动的线程中的第一个动作同步。” [来自17.4.4] - Trevor Freeman

网页内容由stack overflow 提供, 点击上面的
可以查看英文原文,
原文链接