Java8:运行Thread示例

时间:2018-01-23 09:44:42

标签: multithreading java-8 thread-safety atomic atomicinteger

我在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 IDE上执行它时,每次运行时它都会给出不同的输出值。想知道是否有人知道它为什么会这样。非常感谢。

3 个答案:

答案 0 :(得分:3)

正如其他人所说,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,但这不会影响此代码的语义

答案 1 :(得分:2)

基本上,线程main所有之前调用shutdownNow已完成的任务(即使没有调用shutdownNow,您仍然看不到{{ 1}},因为你在执行者完成之前仍在查询2000

你真的想要阻止,直到你的执行者完成或发生超时:

AtomicInteger

如果您仔细查看帖子的作者,那么这些文章来自定义:

executor.shutdown();
executor.awaitTermination(100, TimeUnit.MILLISECONDS);

答案 2 :(得分:1)

shutdownNow的JavaDoc说:

  

尝试停止所有正在执行的任务,停止处理   等待任务,并返回正在等待的任务列表   执行。

     

此方法不等待主动执行任务终止。   使用awaitTermination来做到这一点。

这样做等待您提交完成的所有任务,所以只需获取设法运行的线程的结果。

要关闭服务并等待所有内容完成,请将shutdownNow替换为:

executor.shutdown();

executor.awaitTermination(10, TimeUnit.SECONDS);

(您需要从某处InterruptedException抓住awaitTermination