Must you join on a Thread to ensure its computation is complete

放肆的年华 提交于 2019-12-29 07:05:10

问题


I have a utility method (used for unit testing, it so happens) that executes a Runnable in another thread. It starts the thread running, but does not wait for the Thread to finish, instead relying on a Future. A caller of the method is expected to get() that Future. But is that enough to ensure safe publication of the computation done by the Runnable?

Here is the method:

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

After calling Future.get() on the returned Future, can the caller of the method safely assume that the Runnable has finished execution, and its results have been safely published?


回答1:


No you don't need to join(). Calling get() on the future is sufficient.

The CompletableFuture interface is a subtype of Future. And the javadoc for Future states this:

Memory consistency effects: Actions taken by the asynchronous computation happen-before actions following the corresponding Future.get() in another thread.

That happen-before relationship is sufficient to ensure safe publication of the value returned by get().

Furthermore, the get() call will not complete until the CompletableFuture has been completed, exceptionally-completed or cancelled.




回答2:


If we look at Safe Publication by Shipilev one of the trivial ways to get safe publication is to work:

Exchange the reference via a volatile field (JLS 17.4.5), or as the consequence of this rule, via the AtomicX classes

Since CompletableFuture uses a volatile field to write and read the value no additional memory barriers are necessary for safe publication. This is explained in 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.

It also handles the safe initialization of the published objects, as per the same overview comment later:

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


来源:https://stackoverflow.com/questions/53733735/must-you-join-on-a-thread-to-ensure-its-computation-is-complete

易学教程内所有资源均来自网络或用户发布的内容,如有违反法律规定的内容欢迎反馈
该文章没有解决你所遇到的问题?点击提问,说说你的问题,让更多的人一起探讨吧!