本教程适用于JDK 8。本页中描述的示例和实践不利用后续版本中引入的改进,并可能使用不再可用的技术。
请参阅Java语言更改了解Java SE 9及后续版本中更新的语言特性的摘要。
请参阅JDK发行说明了解所有JDK版本的新功能、增强功能以及已删除或弃用的选项的信息。
内存一致性错误发生在不同的线程对相同数据有不一致的视图时。内存一致性错误的原因很复杂,超出了本教程的范围。幸运的是,程序员不需要对这些原因有详细的了解。所需的只是避免这些错误的策略。
避免内存一致性错误的关键在于理解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
返回时,终止线程执行的所有语句与成功加入之后的所有语句存在happens-before关系。线程中的代码的效果现在对执行join操作的线程可见。有关创建happens-before关系的操作列表,请参考java.util.concurrent包的概要页面。