【问题标题】:synchronized and ExecutorService on Java 8 [duplicate]Java 8 上的同步和 ExecutorService [重复]
【发布时间】:2017-10-26 15:20:57
【问题描述】:

我的期望是程序会返回输出“1000”。

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

Counter 类的 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());

    }

}

【问题讨论】:

  • 这个问题没有直接针对 AtomicInteger 类。

标签: java concurrency parallel-processing executorservice synchronized


【解决方案1】:

你的逻辑很好。

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

将您的代码更改为:

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

【讨论】:

  • 或使用executor.shutdown();while(!executor.isTerminated()) {} 阻塞,直到所有任务都完成,无需任意时间等待。
  • 知道了。谢谢。
  • @Mena executor.shutdown();while(!executor.isTerminated()) {} 是个坏主意。这将导致忙等待和高 CPU 使用率。 awaitTermination 更好。
  • @Malt 我同意,这是一个非常糟糕的主意。我的观点只是提供一个廉价的测试解决方案,因为等待任意超时终止可能无法满足完成任意任务的时间要求。从不同线程聚合增量的正确方法可能不在于首先使用ExecutorService
【解决方案2】:

您的问题的答案是,在打印 contador 的值之前,您无需等待所有 Runnables 完成。

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

编辑:

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

例如,如果线程 A 正在递增的过程中,线程 B 调用 getValue 时应该看到什么?它应该看到旧值,还是应该等到线程 A 完成才能获得最新值?

【讨论】:

  • 知道了。谢谢。
【解决方案3】:

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

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());
}

【讨论】:

  • 知道了。谢谢。
  • 是的,但是解释一下为什么它应该是这样的呢?
猜你喜欢
  • 2015-02-15
  • 2012-03-02
  • 2015-11-05
  • 2021-12-01
  • 1970-01-01
  • 1970-01-01
  • 2020-03-16
  • 2011-09-20
  • 2016-05-08
相关资源
最近更新 更多