Java 教程是为 JDK 8 编写的。本页中描述的示例和实践未利用在后续版本中引入的改进。
考虑一个名为 的简单类Counter
class Counter {
private int c = 0;
public void increment() {
c++;
}
public void decrement() {
c--;
}
public int value() {
return c;
}
}
Counter 的设计是为了每次调用 increment 都会将 1 加到 c,并且每次调用 decrement 都会从 c 减去 1。但是,如果从多个线程引用 Counter 对象,则线程之间的干扰可能会导致这种情况不按预期发生。
当两个操作在不同的线程中运行但作用于相同的数据时,会发生干扰,interleave (交错)。这意味着这两个操作由多个步骤组成,并且步骤顺序重叠。
对于 Counter 实例的操作似乎不可能出现交错,因为 c 上的两个操作都是单个简单语句。但是,即使是简单的语句也可以由虚拟机转换为多个步骤。我们不会检查虚拟机采取的具体步骤 只需要知道单个表达式 c++ 可以分解为三个步骤:
c 的当前值。c。除了第二步递减而不是递增之外,表达式 c-- 可以以相同的方式分解。
假设线程 A 调用 increment,同时线程 B 调用 decrement。如果 c 的初始值为 0,则它们的交错操作可能遵循以下顺序:
线程 A 的结果丢失,被线程 B 覆盖。这种特殊的交错只是一种可能性。在不同情况下,可能是线程 B 的结果丢失,或者根本没有错误。因为它们是不可预测的,所以线程干扰错误难以检测和修复。