12

我目前正在学习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吗?相反,结果总是不同的。

4

3 回答 3

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

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

于 2013-09-24T08:18:10.363 回答
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);
}
于 2013-09-24T08:19:39.830 回答
2

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

于 2013-09-24T08:18:53.663 回答