Java:线程连接超过 10,000 次迭代不一致

Java: Thread joins over 10,000 iterations inconsistent

好的伙计们..我又回来了(最近好像是我的家)。

我正在经历在多线程上编写 YouTube 视频的整个过程。这个特定的线程使用 2 个线程,这些线程通过一个 for 循环,每次将 1 加到变量 10,000 次。所以你加入他们,所以完成后结果是 20,000。

public class main {

private int count = 0;

public static void main(String[] args) {
   main main = new main();
   main.doWork();
}

public void doWork(){

    Thread t1 = new Thread(new Runnable(){
        public void run(){

            for (int i = 0; i < 10000; i++){
                count++;
            }
        }
    });

    Thread t2 = new Thread(new Runnable(){
        public void run(){

            for (int i = 0; i < 10000; i++){
                count++;
            }
        }
    });

    t1.start();
    t2.start();

    try {
        t1.join();
        t2.join();
    } catch (InterruptedException ex) {
        Logger.getLogger(main.class.getName()).log(Level.SEVERE, null, ex);
    }


    System.out.println("Count is: " + count);
    }
} 

事情是..当我改变迭代时:

i < 10 = 20(正确)

i < 100 = 200(正确)

i < 1000 = 2000(正确)

i < 10000 = 13034 (第一个 运行)

= 14516(第二个运行)

= ...等等..

为什么它不能正确处理数以万计的迭代?

您已经演示了经典的竞争条件,当 2 个或更多线程以冲突的方式读取和写入同一个变量时,就会发生这种情况。出现这种情况是因为 ++ 运算符不是原子操作——正在发生多个操作,并且线程可能会在操作之间中断,例如:

  1. 线程t1读取count0),并计算增量值(1),但它还没有将值存储回count还没有。
  2. 线程t2读取count(仍然是0),并计算增量值(1),但它还没有将值存储回count还没有。
  3. 线程 t1 将其 1 值存储回 count
  4. 线程 t2 将其 1 值存储回 count

发生了两次更新,但最终结果只增加了 1。不能被中断的一组操作是临界区

这似乎发生了 20,000 - 13,034 次,或者在您的第一次处决中发生了 6,966 次。您可能对下限很幸运,但无论界限的大小如何,竞争条件都可能发生。

在Java中有几种解决方法:

  1. 在关键部分(count++ 行)周围放置 synchronized blocks,锁定 this
  2. count 更改为 AtomicInteger,它自己以原子方式封装此类操作。 getAndIncrement 方法将替换此处的 ++ 运算符。