内存一致性错误

当不同的线程对应为相同数据的视图不一致时,将发生内存一致性错误。内存一致性错误的原因很复杂,超出了本教程的范围。幸运的是,程序员不需要详细了解这些原因。所需要的只是避免它们的策略。

避免内存一致性错误的关键是了解事前发生的关系。这种关系只是对一个特定语句的内存写入对另一特定语句可见的保证。要查看此内容,请考虑以下示例。假设定义并初始化了一个简单的int字段:

int counter = 0;

counter字段在两个线程 A 和 B 之间共享。假设线程 A 递增counter

counter++;

然后,不久之后,线程 B 打印出counter

System.out.println(counter);

如果两个语句是在同一线程中执行的,则可以安全地假定打印出的值为“ 1”。但是,如果两个语句在单独的线程中执行,则打印出的值很可能是“ 0”,因为无法保证线程 B 将线程 A 更改为counter的行为是可见的-除非程序员在这两个 语句。

有几种动作可以创建事前发生的关系。其中之一是同步,正如我们将在以下各节中看到的。

我们已经看到了两个创建先于关系的动作。

  • 当一个语句调用Thread.start时,与该语句具有事前发生关系的每个语句也与由新线程执行的每个语句都具有事前发生关系。导致创建新线程的代码效果对新线程可见。

  • 当一个线程终止并导致另一个线程中的Thread.join返回时,终止线程执行的所有语句与成功连接之后的所有语句都具有“先发生后发生”关系。现在,执行连接的线程可以看到线程中代码的效果。

有关创建事前发生关系的操作的列表,请参见java.util.concurrent 包的摘要页面。