Java 8 上的同步和 ExecutorService

synchronized and ExecutorService on Java 8

我的预期是程序会 return 输出“1000”。

但是,程序每次执行都会出现不同的输出。

计数器 class 的 increment() 方法已同步。只有这样才能避免竞争读数吗?

让它计算 1000 个增量的正确方法是什么?

package app;

public class Counter {

    private Integer value;

    public Counter(int initialValue) {
        value = initialValue;
    }

    public synchronized void increment() {
        value = value + 1;          
    }

    public int getValue() {
        return value;
    }

}

package app;

import java.util.concurrent.ExecutorService;
import java.util.concurrent.Executors;

public class Main {

    public static void main(String[] args) {

        Counter contador = new Counter(0);

        ExecutorService executor = Executors.newFixedThreadPool(10);

        for(int i = 0; i < 1000; i++) {
            executor.submit(() -> {
                contador.increment();   
            });     
        }

        System.out.println(contador.getValue());

    }

}

您的问题的答案是您没有等待所有 Runnables 完成后再打印 contador 的值。

所以有时只调用了 20 次增量调用,有时调用了 50 次,等等

编辑:

仔细观察,我认为您的线程安全性存在潜在问题。您已同步增量值。 getValue 方法应该匹配吗?

比如线程A在自增过程中,线程B在调用getValue时应该看到什么?它应该看到旧值,还是应该等到线程 A 完成后再获取最新值?

你的逻辑没问题。

问题是您在线程完成递增之前打印了计数器的值。

将您的代码更改为:

for(int i = 0; i < 1000; i++) {
    executor.submit(() -> {
        contador.increment();   
    });     
}

executor.shutdown(); //Shut down the executor

//Wait until the threads have stopped. A maximum of 1 minute is more than enough
executor.awaitTermination(1, TimeUnit.MINUTES); 

System.out.println(contador.getValue()); //prints 1000

这是您的主要方法的外观:

public static void main(String[] args) {
    Counter contador = new Counter(0);
    ExecutorService executor = Executors.newFixedThreadPool(10);
    for(int i = 0; i < 1000; i++) {
        executor.submit(() -> {
            contador.increment();
        });
    }
    executor.shutdown();
    try {
        executor.awaitTermination(Long.MAX_VALUE, TimeUnit.NANOSECONDS);
    } catch (InterruptedException e) {
    }
    System.out.println(contador.getValue());
}