奇怪的并发代码行为

bvk*_*256 12 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);
    }
}
Run Code Online (Sandbox Code Playgroud)

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

Mar*_*nik 25

  1. executorService.shutdown()不等待服务关闭.你需要打个电话awaitTermination.

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

  • @ bvk256 - 鉴于您已经在使用`synchronized`,最好编写一个同步的getter方法来获取最终结果.(使用`synchronized`*和*a` volatile`变量可能效率低下.) (2认同)