Documentation

The Java™ Tutorials
Hide TOC
Thread Interference线程干涉
Trail: Essential Java Classes
Lesson: Concurrency
Section: Synchronization

Thread Interference线程干涉

Consider a simple class called Counter考虑一个简单的叫做Counter的类

class Counter {
    private int c = 0;

    public void increment() {
        c++;
    }

    public void decrement() {
        c--;
    }

    public int value() {
        return c;
    }

}

Counter is designed so that each invocation of increment will add 1 to c, and each invocation of decrement will subtract 1 from c. Counter的设计使得每次调用increment将向c添加1,每次调用decrement将从c中减去1。However, if a Counter object is referenced from multiple threads, interference between threads may prevent this from happening as expected.但是,如果Counter对象是从多个线程引用的,线程之间的干扰可能会阻止这种情况发生。

Interference happens when two operations, running in different threads, but acting on the same data, interleave. 当在不同线程中运行但作用于相同数据的两个操作交错时,就会发生干扰。This means that the two operations consist of multiple steps, and the sequences of steps overlap.这意味着这两个操作由多个步骤组成,并且步骤序列重叠。

It might not seem possible for operations on instances of Counter to interleave, since both operations on c are single, simple statements. Counter实例上的操作似乎不可能交错,因为c上的两个操作都是单个简单语句。However, even simple statements can translate to multiple steps by the virtual machine. 然而,即使是简单的语句也可以通过虚拟机转换为多个步骤。We won't examine the specific steps the virtual machine takes — it is enough to know that the single expression c++ can be decomposed into three steps:我们不会检查虚拟机采取的具体步骤—单表达式c++可以分解为三个步骤:

  1. Retrieve the current value of c.检索c的当前值。
  2. Increment the retrieved value by 1.将检索到的值增加1。
  3. Store the incremented value back in c.将递增的值存储回c

The expression c-- can be decomposed the same way, except that the second step decrements instead of increments.表达式c--可以用同样的方式分解,除了第二步是递减而不是递增。

Suppose Thread A invokes increment at about the same time Thread B invokes decrement. 假设线程A调用increment的时间与线程B调用decrement的时间大致相同。If the initial value of c is 0, their interleaved actions might follow this sequence:如果c的初始值为0,则它们的交错操作可能遵循以下顺序:

  1. Thread A: Retrieve c.线程A:检索c。
  2. Thread B: Retrieve c.线程B:检索c。
  3. Thread A: Increment retrieved value; result is 1.线程A:增量检索值;结果是1。
  4. Thread B: Decrement retrieved value; result is -1.线程B:减量检索值;结果是-1。
  5. Thread A: Store result in c; c is now 1.线程A:将结果存储在c中;c现在是1。
  6. Thread B: Store result in c; c is now -1.线程B:将结果存储在c中;c现在是-1。

Thread A's result is lost, overwritten by Thread B. 线程A的结果丢失,被线程B覆盖。This particular interleaving is only one possibility. 这种特殊的交织只是一种可能性。Under different circumstances it might be Thread B's result that gets lost, or there could be no error at all. 在不同的情况下,可能是线程B的结果丢失了,或者根本没有错误。Because they are unpredictable, thread interference bugs can be difficult to detect and fix.因为它们是不可预测的,所以线程干扰bug可能很难检测和修复。


Previous page: Synchronization
Next page: Memory Consistency Errors