英文:
Understanding CompletableFuture simple implementation
问题
考虑以下代码,取自这篇文章。它实现了类似于CompletableFuture的内容,用于学习目的。
这是WaitingFuture
的get()
函数:
@Override
public V get() throws ExecutionException {
this.thread = Thread.currentThread();
LockSupport.park(this);
if (throwable != null) {
throw new ExecutionException(throwable);
}
return result;
}
这是RunnableWaitingFuture
的run()
函数:
@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);
之后被调用,导致线程永远处于等待状态。这是真的吗?
英文:
Consider the following code taken from this article. It implements something similar to a CompletableFuture for learning purposes.
Here's the get()
function of WaitingFuture
:
@Override
public V get() throws ExecutionException {
this.thread = Thread.currentThread();
LockSupport.park(this);
if (throwable != null) {
throw new ExecutionException(throwable);
}
return result;
}
And here's the run()
function of RunnableWaitingFuture
:
@Override
public void run() {
try {
waitingFuture.result = userFunction.get();
} catch (Throwable throwable) {
waitingFuture.throwable = throwable;
} finally {
waitingFuture.finished = true;
LockSupport.unpark(waitingFuture.thread);
}
}
}
The Question:
It seems to me that if run()
will finish before get()
is even called then LockSupport.park(this);
will be called after LockSupport.unpark(waitingFuture.thread)
, leaving the thread parking forever.
Is that true?
答案1
得分: 4
park()
/unpark()
与wait
/notify
不同,因为如果在park()
之前调用了unpark
,信号不会丢失。
然而,仍然只有一个单独的位来记录调用了多少次unpark
,所以不能假设所有的调用都会完美配对。
此外,park
在被中断时会静默返回,甚至可以出现虚假唤醒,也就是无故返回。
换句话说,即使从park()
返回,也不能保证条件已经满足。和其他通知机制一样,没有办法避免在循环中使用它。
引用的代码更糟糕,因为它涉及到thread
变量的另一个竞态条件。不能保证在另一个线程读取它以通知它的时候,它已经被写入。
英文:
park()
/unpark()
is different to wait
/notify
, as the signal won’t be lost if unpark
has been called before park()
.
However, it’s still only a single bit that doesn’t count how often unpark
has been called, so it’s still wrong to assume that all calls will be perfectly paired.
Further, park
will silently return on interrupts and is even allowed to return spuriously, which means for no reason.
In other words, even returning from park()
doesn’t guaranty that the condition has been fulfilled. Just like with the other notification mechanisms, there is no way around using it in a loop.
The cited code is even worse, as it has another race condition regarding the thread
variable. There is no guaranty that it has been written at the point where the other thread reads it for notifying it.
答案2
得分: 2
是的。
while (!waitingFuture.finished) {
LockSupport.park(this);
}
一般来说,LockSupport.park功能过于低级,应该使用Object::wait
或Condition::await
来提高可靠性。
英文:
yes.
LockSupport.park(this);
should be replaced with something like
while (!waitingFuture.finished) {
LockSupport.park(this);
}
Generally, LockSupport.park is too low a feature, and Object::wait
or Condition::await
should be used instead for reliability.
通过集体智慧和协作来改善编程学习和解决问题的方式。致力于成为全球开发者共同参与的知识库,让每个人都能够通过互相帮助和分享经验来进步。
评论