如果两个不同步的线程将计数器增加X倍,总结果是否小于X?

我在一个紧密的循环中有两个未同步的线程,将全局变量X递增(x = 100000)。

正确的全局最终值应为2 * X,但是由于它们不同步,因此会更少,根据经验,它通常仅比X小一点

但是,在所有测试运行中,global的值永远不会低于X。

最终结果是否有可能小于x(小于100000)?

public class TestClass {
    static int global;
    public static void main(String[] args) throws InterruptedException {
        Thread t = new Thread( () -> {  for(int i=0; i < 100000; ++i) {     TestClass.global++;  }  });
        Thread t2 = new Thread( () -> { for(int i=0; i < 100000; ++i) {     TestClass.global++;  }  });
        t.start(); t2.start();
        t.join(); t2.join();
        System.out.println("global = " + global);
    }
}
lyjzqxg188 回答:如果两个不同步的线程将计数器增加X倍,总结果是否小于X?

试想一下以下情况:

  • 线程A从0读取初始值global
  • 线程B在global上执行99999更新
  • 线程A将1写入global
  • 线程B从1读取global
  • 线程A在global上执行其剩余的99999更新
  • 线程B将2写入global

然后,两个线程均已完成,但结果值为2,而不是2 * 100000100000

请注意,以上示例仅使用了错误的计时,而没有让任何线程感知到对其他线程的读取或写入乱序(在没有同步的情况下是允许的),也没有丢失更新(也可以进行更新)这里)。

换句话说,当将global变量声明为volatile时,上述情况甚至有可能。

推理和读写及其可见性是一个常见的错误,但隐含地假定了执行线程代码的特定时间。但是,不能保证这些线程以相似的指令时间并排运行。

但是在您的测试场景中仍然可能会发生这种情况,因此它们没有揭示其他可能的行为。同样,某些法律行为可能永远不会发生在特定的硬件或特定的JVM实现上,而开发人员仍然必须对此加以考虑。优化器可能会用等效的global += 100000代替递增循环,这在这种测试中很少显示中间值,但是在循环体中插入其他一些非平凡的操作可能会改变行为完全。

本文链接:https://www.f2er.com/2911879.html

大家都在问