我在winterbe.com上看到了下面的示例,它演示了原子变量的使用。
// From http://winterbe.com/posts/2015/05/22/java8-concurrency-tutorial-atomic-concurrent-map-examples/
public class Test_AtomicInteger {
public static void main(String[] args) {
AtomicInteger atomicInt = new AtomicInteger(0);
ExecutorService executor = Executors.newFixedThreadPool(2);
IntStream.range(0, 1000)
.forEach(i -> {
Runnable task = () ->
atomicInt.updateAndGet(n -> n + 2);
executor.submit(task);
});
executor.shutdownNow();
System.out.println(atomicInt.get()); // => 2000
}
}了解预期值2000是如何从线程安全场景中推导出来的。但是,当我试图在eclipse上执行它时,每次运行时,它都会给出不同的输出值。想看看有没有人知道它为什么会这样。非常感谢。
发布于 2018-01-23 10:25:17
基本上,线程main是在所有已执行的任务完成之前调用shutdownNow (即使没有调用shutdownNow,仍然看不到2000,因为在执行程序完成之前仍在查询AtomicInteger )。
在执行程序完成或超时之前,您确实希望阻止:
executor.shutdown();
executor.awaitTermination(100, TimeUnit.MILLISECONDS);如果你仔细看了这篇文章的作者,这是从定义:
public static void stop(ExecutorService executor) {
try {
executor.shutdown();
executor.awaitTermination(60, TimeUnit.SECONDS);
}
....发布于 2018-01-23 11:10:55
正如其他人所说的,shutdownNow()是不合适的,因为它可能导致排队的任务被放弃,同时不等待当前正在运行的任务的完成。
一个正确的序列是shutdown(),后面是awaitTermination,但是,您可以做同样简单得多的操作:
AtomicInteger atomicInt = new AtomicInteger(0);
ExecutorService executor = Executors.newFixedThreadPool(2);
executor.invokeAll(Collections.nCopies(1000, () -> atomicInt.updateAndGet(n -> n + 2)));
System.out.println(atomicInt.get()); // => 2000
executor.shutdown(); // only for cleanup在这里,invokeAll将调用所有任务,所有这些任务都可以并发运行,并等待所有任务的完成。执行器甚至不需要被关闭,但是可以在其他任务中重用,但是,一旦不再需要它,就应该关闭它来清理底层资源。
Collections.nCopies是获取相同元素的List的最简单方法,甚至无需存储这些引用。
因为invokeAll需要一个Callable的列表,而不是Runnable的,所以任务将是Callable,但这并不影响代码的语义。
发布于 2018-01-23 10:06:39
JavaDoc for shutdownNow说:
尝试停止所有正在执行的任务,停止等待任务的处理,并返回等待执行的任务列表。 此方法不等待主动执行任务终止。使用awaitTermination来完成这个任务。
因此,这会使而不是等待提交给您完成的所有任务,所以只需获得成功运行的线程的结果即可。
若要关闭服务并等待一切完成,请将shutdownNow替换为如下所示:
executor.shutdown();
executor.awaitTermination(10, TimeUnit.SECONDS);(您需要从InterruptedException的某个地方捕获awaitTermination )。
https://stackoverflow.com/questions/48398550
复制相似问题