代码之家  ›  专栏  ›  技术社区  ›  zonyang

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

  •  0
  • zonyang  · 技术社区  · 6 年前

    在这段代码中,我使用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);
        } 
    }
    
    0 回复  |  直到 6 年前
        1
  •  2
  •   Vladimir Pligin    6 年前

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

    1. 你不会等每一个 Thread 正确完成工作。实现这一目标有多种方法,最简单的是 Thread.join() .
    2. 你的单例实现似乎不正确。我想您打算用一个内部类来实现它。看来这个 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);