我目前正在学习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吗?相反,结果总是不同的。
答案 0 :(得分:25)
executorService.shutdown()
不等待服务关闭。您需要致电awaitTermination
。
您无需锁定即可从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。因此,每次获取任意输出都是预期的行为。