您是否必须加入线程以确保其计算完成

时间:2018-12-11 23:10:27

标签: java multithreading future

我有一个实用程序方法(用于单元测试,确实如此),它在另一个线程中执行Runnable。它启动线程运行,但不等待Thread完成,而是依靠Future。该方法的调用者应get() Future。但这足以确保由Runnable完成的计算的安全发布吗?

这是方法:

private static Future<Void> runInOtherThread(final CountDownLatch ready, final Runnable operation) {
    final CompletableFuture<Void> future = new CompletableFuture<Void>();
    final Thread thread = new Thread(() -> {
        try {
            ready.await();
            operation.run();
        } catch (Throwable e) {
            future.completeExceptionally(e);
            return;
        }
        future.complete(null);
    });
    thread.start();
    return future;
}

在返回的Future.get()上调用Future之后,方法的调用者是否可以安全地假定Runnable已完成执行,并且其结果已安全发布?

2 个答案:

答案 0 :(得分:3)

否,您不需要join()。将来致电get()就足够了。

CompletableFuture接口是Future的子类型。 Future的{​​{3}}指出:

  

内存一致性影响:在另一个线程中,相应的Future.get()之后的异步计算 happen-before 操作采取的操作。

先发生关系足以确保安全发布get()返回的值。

此外,get()的调用在CompletableFuture完成,异常完成或取消之前不会完成。

答案 1 :(得分:1)

如果我们看一下Shipilev的Safe Publication,那么获得安全发表的简单方法之一就是工作:

  

通过volatile字段(JLS 17.4.5)或通过此规则通过AtomicX类交换引用

由于CompletableFuture使用volatile字段来写入和读取该值,因此不需要其他内存屏障即可安全发布。 CompletableFuture class overview comment中对此进行了解释:

 * A CompletableFuture may have dependent completion actions,
 * collected in a linked stack. It atomically completes by CASing
 * a result field, and then pops off and runs those actions. This
 * applies across normal vs exceptional outcomes, sync vs async
 * actions, binary triggers, and various forms of completions.
 *
 * Non-nullness of volatile field "result" indicates done.  It may
 * be set directly if known to be thread-confined, else via CAS.
 * An AltResult is used to box null as a result, as well as to
 * hold exceptions.

它还会处理已发布对象的安全初始化,如稍后相同的概述注释所述:

 * Completion fields need not be declared as final or volatile
 * because they are only visible to other threads upon safe
 * publication.