奇怪的并发代码行为

时间:2013-09-24 08:11:20

标签: java multithreading

我目前正在学习Java并发。我对代码行为的方式感到非常惊讶。

import java.util.concurrent.*;

public class Exercise {
    static int counter = 0;

    static synchronized int getAndIncrement() {
        return counter++;
    }

    static class Improper implements Runnable {

        @Override
        public void run() {
            for (int i = 0; i < 300; i++) {
                getAndIncrement();
            }
        }
    }


    public static void main(String[] args) {
        ExecutorService executorService = Executors.newFixedThreadPool(3);
        for (int i = 0; i < 300; i++) {
            executorService.submit(new Improper());
        }
        executorService.shutdown();
        System.out.println(counter);
    }
}

它不应该一直输出90000吗?相反,结果总是不同的。

3 个答案:

答案 0 :(得分:25)

  1. executorService.shutdown()不等待服务关闭。您需要致电awaitTermination

  2. 您无需锁定即可从main方法访问counter。如果您等待执行程序服务关闭,我认为您将勉强逃脱数据竞争,但请注意,一般情况下,您必须同步共享变量的所有访问,而不仅仅是写入,从Java内存模型中获得任何可见性保证。

答案 1 :(得分:3)

您需要确保所有任务都有时间终止。使用awaitTermination

public static void main(String[] args) throws InterruptedException {
    ExecutorService executorService = Executors.newFixedThreadPool(3);
    for (int i = 0; i < 300; i++) {
        executorService.submit(new Improper());
    }
    executorService.shutdown();
    executorService.awaitTermination(2, TimeUnit.SECONDS);
    System.out.println(counter);
}

答案 2 :(得分:2)

您不等待所有提交的任务终止,请参阅ExecutorService.html#shutdown的javadoc。因此,每次获取任意输出都是预期的行为。