Java 教程是为 JDK 8 编写的。本页中描述的示例和实践未利用在后续版本中引入的改进。
当不同的线程具有应该是相同数据的不一致视图时,会发生 Memory consistency errors (内存一致性错误)。内存一致性错误的原因很复杂,超出了本教程的范围。幸运的是,程序员不需要详细了解这些原因。所需要的只是一个避免它们的策略。
避免内存一致性错误的关键是理解 happens-before (发生之前) 关系。这种关系只是保证一个特定语句的内存写入对另一个特定语句可见。为了理解这点,考虑如下的示例。假设定义并初始化了一个简单的 int
字段:
int counter = 0;
counter
字段在两个线程 A 和 B 之间共享。假设线程 A 递增 counter
:
counter++;
然后,不久之后,线程 B 打印出 counter
:
System.out.println(counter);
如果两个语句已在同一个线程中执行,则可以安全地假设打印出的值为“1”。但是如果这两个语句是在不同的线程中执行的,那么打印出的值可能是“0”,因为不能保证线程 A 对 counter
的更改对线程 B 可见。除非程序员在这两个语句之间建立了 happens-before 关系。
有几种方式可以创建 happens-before 关系。其中之一是同步,我们将在以下部分中看到。
我们已经看到了两种建立 happens-before 关系的操作。
Thread.start
时,与该语句具有一个 happens-before 的每个语句,也与新线程执行的每个语句都有一个 happens-before 关系。导致创建新线程的代码的影响,是新线程是可见的。Thread.join
返回时,终止线程执行的所有语句与成功 join 后的所有语句都有一个 happens-before 关系。现在,线程中代码的效果对执行 join 的线程是可见的。有关创建 happens-before 的操作列表,请参阅 java.util.concurrent
包的摘要页。