线程内一致性
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:分配
i = 1
- 线程 2:分配
i = 0
- 线程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
。
代码简单
// 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:分配
i = 1
- 线程 2:分配
i = 0
- 线程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
。