Вы должны присоединиться к потоку, чтобы убедиться, что его вычисления завершены - PullRequest
0 голосов
/ 12 декабря 2018

У меня есть служебный метод (используемый для модульного тестирования, так бывает), который выполняет 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 голосов
/ 12 декабря 2018

Нет, вам не нужно join().Вызова get() на будущее достаточно.

Интерфейс CompletableFuture является подтипом Future javadoc для Future утверждает следующее:

Эффекты согласованности памяти: действия, предпринятые асинхронным вычислением произойти до действия после соответствующих Future.get() в другом потоке.

То, что отношение произойдет до достаточно для безопасной публикации значения, возвращаемого get().

Кроме того, get() вызов не будет завершен до тех пор, пока CompletableFuture не будет завершен, исключительно завершен или отменен.

0 голосов
/ 12 декабря 2018

Если мы посмотрим на Safe Publication Шипилева, один из тривиальных способов получить безопасную публикацию - это работать:

Обмен ссылками через изменчивое поле (JLS 17.4.5) или как следствие этого правила, через классы AtomicX

Поскольку CompletableFuture использует поле volatile для записи и чтения значения, для безопасной публикации не требуется никаких дополнительных барьеров памяти.Это объясняется в CompletableFuture комментарии к обзору классов :

 * 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.
...