考虑从这篇文章获取的以下代码。为了学习目的,它实现了类似于CompletableFuture的东西。
这是get()的WaitingFuture函数
@Override
public V get() throws ExecutionException {
this.thread = Thread.currentThread();
LockSupport.park(this);
if (throwable != null) {
throw new ExecutionException(throwable);
}
return result;
}这是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()被调用之前就完成了,那么LockSupport.park(this);就会在LockSupport.unpark(waitingFuture.thread)之后被调用,留下线程永远停在那里。
这是真的吗?
发布于 2020-08-17 16:06:28
park()/unpark()不同于wait/notify,因为如果unpark在park()之前被调用,那么信号不会丢失。
然而,它仍然只是一个不计算unpark被调用的频率的一点,所以假设所有调用都将完美配对仍然是错误的。
此外,park将在中断时默默地返回,甚至允许伪造返回,这意味着没有任何理由。
换句话说,即使从park()返回也不能保证条件已经满足。就像其他通知机制一样,在循环中使用它是没有办法的。
引用的代码更糟糕,因为它对thread变量有另一个竞争条件。没有保证它是在另一个线程读取它以通知它的时候写的。
发布于 2020-08-17 15:55:03
是。
LockSupport.park(this);应该用这样的东西代替
while (!waitingFuture.finished) {
LockSupport.park(this);
}通常,LockSupport.park的特性太低,为了可靠性,应该使用Object::wait或Condition::await。
https://stackoverflow.com/questions/63452789
复制相似问题