Warning: file_get_contents(/data/phpspider/zhask/data//catemap/6/multithreading/4.json): failed to open stream: No such file or directory in /data/phpspider/zhask/libs/function.php on line 167

Warning: Invalid argument supplied for foreach() in /data/phpspider/zhask/libs/tag.function.php on line 1116

Notice: Undefined index: in /data/phpspider/zhask/libs/function.php on line 180

Warning: array_chunk() expects parameter 1 to be array, null given in /data/phpspider/zhask/libs/function.php on line 181
Multithreading Java8:运行线程示例的问题_Multithreading_Java 8_Thread Safety_Atomic_Atomicinteger - Fatal编程技术网

Multithreading Java8:运行线程示例的问题

Multithreading Java8:运行线程示例的问题,multithreading,java-8,thread-safety,atomic,atomicinteger,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 = n

我在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是如何从线程安全场景中推导出来的。然而,当我试图在EclipseIDE上执行它时,每次运行时它都会给出不同的输出值。我想看看是否有人知道它为什么会这样。非常感谢。

关闭现在的JavaDoc说:

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

此方法不会等待主动执行的任务终止。 使用此选项可以完成此操作

因此,这不会等待您提交的所有任务完成,因此只需获取成功运行的线程的结果即可

要关闭服务并等待一切完成,请将
shutdownNow
替换为以下内容:

executor.shutdown();

executor.awaitTermination(10, TimeUnit.SECONDS);

(您需要从
等待终止
的某个地方捕获
中断异常

基本上,线程
main
在执行所有任务之前正在调用
shutdownow
(即使不调用
shutdownNow
您仍然看不到
2000
,因为您仍然在执行器完成之前查询
AtomicInteger

您确实希望阻止,直到执行器完成或超时:

executor.shutdown();
executor.awaitTermination(100, TimeUnit.MILLISECONDS);
如果你仔细阅读这篇文章的作者,你会发现:

 public static void stop(ExecutorService executor) {
    try {
        executor.shutdown();
        executor.awaitTermination(60, TimeUnit.SECONDS);
    }

    ....

正如其他人所说,
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
是获取相同元素的
列表
的最简单方法,它甚至不需要存储来保存那个数量的引用


由于
invokeAll
需要一个
Callable
s列表,而不是
Runnable
s列表,因此任务将是
Callable
s,但这不会影响此代码的语义。

@Holger编辑,谢谢。我想用
invokeAll
发布一些东西,只是想不出如何很好地完成它。我也会这样做假设
List List=Collections.nCopies(1000,()->atomicInt.updateAndGet(n->n+2))
将需要强制转换,因为它也可能是
供应商
,但我猜目标类型也会被考虑在内(因为java-8对吗?)因此不需要强制转换,目标类型告诉它,否则,它可以是任何东西,而不仅仅是
供应商
可调用的
。没有目标类型,lambda几乎无法使用,所以很明显,为什么在Java 8中添加了它……感谢您的解释!