在多个线程中更新 AtomicInteger 变量时未获得预期结果

Not getting expected result when updating AtomicInteger variable in multiple threads

在这段代码中,我使用了 10 个线程来更新一个 AtomicInteger 变量。我希望 Counter.getInstance().holder.n 的最终结果为 1000000,但它会打印出随机数,如 991591。 我的代码有什么问题?

public class Test {


    public static void main(String[] args) {

        List<Thread> list = new ArrayList<Thread>();
        for (int i = 0; i < 10; i++) {
            list.add(new Thread() {

                public void run() {
                    for (int i = 0; i < 100000; i++) {
                        Counter.getInstance().holder.n.incrementAndGet();
                    }
                }
            });
        }
        for (Thread thread : list) {
            thread.start();
        }

        try {
            Thread.sleep(10000);
        } catch (InterruptedException e) {
            e.printStackTrace();
        }

        System.out.println(Counter.getInstance().holder.n);


    } 
} 

class Counter {
    private static Counter counter;
    Holder holder = new Holder();


    public static Counter getInstance() {
        if (counter == null) {
            counter = new Counter();
        }
        return counter;
    }
    class Holder {
        AtomicInteger n = new AtomicInteger(0);
    } 
}

这里有两个主要的并发问题:

  1. 您不必等待每个 Thread 都正确完成工作。有多种方法可以实现,最简单的是使用 Thread.join().
  2. 您的单例实现似乎不正确。我想你打算用一个内部 class 来实现它。看来这个 answer 可以帮助理解这里发生的事情。

下面的实现似乎或多或少是正确的。

class Test {
    public static void main(String[] args) throws InterruptedException {

        List<Thread> list = new ArrayList<Thread>();
        for (int i = 0; i < 10; i++) {
            list.add(new Thread() {

                public void run() {
                    for (int i = 0; i < 100000; i++) {
                        Counter.getInstance().n.incrementAndGet();
                    }
                }
            });
        }
        for (Thread thread : list) {
            thread.start();
        }

        for (Thread thread : list) {
            thread.join();
        }

        System.out.println(Counter.getInstance().n);
    }
}

class Counter {
    public AtomicInteger n = new AtomicInteger(0);

    public static Counter getInstance() {
        return Holder.instance;
    }
    private static class Holder {
        private static final Counter instance = new Counter();
    }
}

您也可以使用 CountDownLatch 之类的东西。例如:

final int count = 10;
CountDownLatch latch = new CountDownLatch(count);
List<Thread> list = new ArrayList<Thread>();
for (int i = 0; i < count; i++) {
    list.add(new Thread() {

        public void run() {
            for (int i = 0; i < 100000; i++) {
                Counter.getInstance().n.incrementAndGet();
            }
            latch.countDown();
        }
    });
}
for (Thread thread : list) {
    thread.start();
}

latch.await();

System.out.println(Counter.getInstance().n);