请考虑以下来自this article的代码。为了学习目的,它实现了类似于CompletableFuture的功能。
这是get()
的{{1}}函数:
WaitingFuture
这是@Override
public V get() throws ExecutionException {
this.thread = Thread.currentThread();
LockSupport.park(this);
if (throwable != null) {
throw new ExecutionException(throwable);
}
return result;
}
的{{1}}函数:
run()
问题:
在我看来,如果RunnableWaitingFuture
将在@Override
public void run() {
try {
waitingFuture.result = userFunction.get();
} catch (Throwable throwable) {
waitingFuture.throwable = throwable;
} finally {
waitingFuture.finished = true;
LockSupport.unpark(waitingFuture.thread);
}
}
}
被调用之前完成,那么run()
将在 get()
之后被调用,从而使线程永远驻留
是真的吗?
答案 0 :(得分:4)
park()
/ unpark()
与wait
/ notify
不同,因为如果在{{1}之前调用unpark
不会丢失信号}}。
但是,仍然只有一点点不计入park()
的呼叫频率,因此,假设所有呼叫都将完美配对仍然是错误的。
此外,unpark
将在中断时静默返回,甚至允许虚假返回,这意味着没有理由。
换句话说,即使从park
返回也不能保证已满足条件。就像其他通知机制一样,无法循环使用它。
所引用的代码更加糟糕,因为它还有一个关于park()
变量的竞争条件。不能保证已在其他线程读取它时将其编写以通知它。
答案 1 :(得分:2)
是。
LockSupport.park(this);
应替换为
while (!waitingFuture.finished) {
LockSupport.park(this);
}
通常,LockSupport.park的功能太低,为了可靠性,应该使用Object::wait
或Condition::await
。