线程内一致性

Intra-thread coherence

代码简单

// not annotated with volatile
public static int I = 0;

public static int test(){
    I = 1;
    return I;
}

有一个线程调用方法test

方法 test 是否可能 return 值“0”?

换句话说,共享变量的读取可能不是看到同一线程的修改。


更新

问题很简单,但我把它弄得晦涩难懂,真的很抱歉。

a thread表示a single thread

问题与 it 重复。

不,它将是 1 如果除了调用该方法的线程之外没有其他线程涉及

chrylis -cautiouslyoptimistic's answer is worth read for an alternative scenario.

两个原因:

  • I 只是被它的所有者改变了,如果另一个线程只是调用 test(),那么它没有选择将 0 作为 I 的值。
  • 第二个线程不会读取Class.I的值,而是test()[=30=的结果 ] 方法。赋值 I=1 发生在 return 之前,因此保证提供最新的更新值(所有者只更新过一次)。

,有可能test方法为return0,如果另一个线程在赋值和赋值之间写入i return 语句:

  1. 线程 1:分配 i = 1
  2. 线程 2:分配 i = 0
  3. 线程1:return i(看到线程2刚刚写的0)

为防止这种情况,所有对 i 的访问、读取和写入都需要在相同条件下同步。使 i 易变不足以防止线程轮流修改它。

请注意,并不是线程 1“看不到”i = 1 写入;这是有保证的,因为所有语句在逻辑上都按程序顺序执行。但是,另一个线程可能会在写入发生之后但在线程 1 读取它之前更改值

任何在 java language specification 上没有用术语解释的答案即使完全正确也只是部分正确。

您需要明确区分在单个线程中发生的操作和由 program order and that in turn creates a happens-before connection 绑定在一起的操作,具体来说是通过:

If x and y are actions of the same thread and x comes before y in program order, then hb(x, y).

这条规则告诉你,如果你在单线程世界中考虑这段代码,它总是会打印 1.

另一方面,在 不同的 线程之间创建 synchronizes with 连接的操作,以及通过以下方式隐式创建 happens-before 的操作:

If an action x synchronizes-with a following action y, then we also have hb(x, y).

在您的例子中,I 是一个 plain 字段,因此与其相关的每个操作都是一个 plain store and/or 一个 普通负载 。根据 JLS,此类存储和加载根本不会创建任何连接。因此,如果涉及写入线程,读取 I 的某些线程始终可以将其读取为0