您必须加入线程以确保其计算完成
Must you join on a Thread to ensure its computation is complete
我有一个实用程序方法(用于单元测试,碰巧)在另一个线程中执行 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
上调用 Future.get()
后,方法的调用者是否可以安全地假设 Runnable
已完成执行,并且其结果已安全发布?
如果我们看看 Shipilev 的 Safe Publication,获得安全发布的一种简单方法就是工作:
Exchange the reference via a volatile field (JLS 17.4.5), or as the consequence of this rule, via the AtomicX classes
由于 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.
不,你不需要 join()
。对未来调用 get()
就足够了。
CompletableFuture
接口是 Future
的子类型。 Future
的 javadoc 表示:
Memory consistency effects: Actions taken by the asynchronous computation happen-before actions following the corresponding Future.get()
in another thread.
happen-before 关系足以确保安全发布 get()
.
返回的值
此外,在 CompletableFuture
完成、异常完成或取消之前,get()
调用不会完成。
我有一个实用程序方法(用于单元测试,碰巧)在另一个线程中执行 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
上调用 Future.get()
后,方法的调用者是否可以安全地假设 Runnable
已完成执行,并且其结果已安全发布?
如果我们看看 Shipilev 的 Safe Publication,获得安全发布的一种简单方法就是工作:
Exchange the reference via a volatile field (JLS 17.4.5), or as the consequence of this rule, via the AtomicX classes
由于 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.
不,你不需要 join()
。对未来调用 get()
就足够了。
CompletableFuture
接口是 Future
的子类型。 Future
的 javadoc 表示:
Memory consistency effects: Actions taken by the asynchronous computation happen-before actions following the corresponding
Future.get()
in another thread.
happen-before 关系足以确保安全发布 get()
.
此外,在 CompletableFuture
完成、异常完成或取消之前,get()
调用不会完成。