理解CompletableFuture简单实现

huangapple go评论81阅读模式
英文:

Understanding CompletableFuture simple implementation

问题

考虑以下代码,取自这篇文章。它实现了类似于CompletableFuture的内容,用于学习目的。

这是WaitingFutureget()函数:

@Override
public V get() throws ExecutionException {
    this.thread = Thread.currentThread();
    LockSupport.park(this);

    if (throwable != null) {
        throw new ExecutionException(throwable);
    }

    return result;
}

这是RunnableWaitingFuturerun()函数:

@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::waitCondition::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.

huangapple
  • 本文由 发表于 2020年8月17日 22:19:04
  • 转载请务必保留本文链接:https://go.coder-hub.com/63452789.html
匿名

发表评论

匿名网友

:?: :razz: :sad: :evil: :!: :smile: :oops: :grin: :eek: :shock: :???: :cool: :lol: :mad: :twisted: :roll: :wink: :idea: :arrow: :neutral: :cry: :mrgreen:

确定