文档

Java™ 教程
隐藏目录
线程干扰
路径:基本的Java类
课程:并发
章节:同步

线程干扰

考虑一个简单的类称为Counter

class Counter {
    private int c = 0;

    public void increment() {
        c++;
    }

    public void decrement() {
        c--;
    }

    public int value() {
        return c;
    }

}

Counter被设计成每次调用increment都会将c加1,而每次调用decrement都会将c减1。然而,如果一个Counter对象被多个线程引用,线程之间的干扰可能会阻止按预期进行。

干扰发生在两个操作在不同线程中运行,但作用于相同的数据时进行交错。这意味着两个操作由多个步骤组成,而且步骤序列是重叠的。

虽然对Counter实例的操作似乎不可能交错,因为对c的两个操作都是单个的简单语句。然而,即使简单的语句也可以被虚拟机转换为多个步骤。我们不会讨论虚拟机执行的具体步骤,知道单个表达式c++可以分解为三个步骤就足够了:

  1. 检索c的当前值。
  2. 将检索到的值增加1。
  3. 将增加后的值存储回c

表达式c--可以以相同的方式分解,只是第二步是减少而不是增加。

假设线程A在大约同一时间调用increment,线程B调用decrement。如果c的初始值为0,它们交错的操作可能按照以下顺序进行:

  1. 线程A:检索c的值。
  2. 线程B:检索c的值。
  3. 线程A:增加检索到的值;结果为1。
  4. 线程B:减少检索到的值;结果为-1。
  5. 线程A:将结果存储在c中;c现在为1。
  6. 线程B:将结果存储在c中;c现在为-1。

线程A的结果被覆盖,被线程B重写。这个特定的交错只是一种可能性。在不同的情况下,可能是线程B的结果被丢失,或者根本没有错误。由于它们是不可预测的,线程干扰错误可能很难检测和修复。


上一页: 同步
下一页: 内存一致性错误