理解 CompletableFuture 简单实现

Understanding CompletableFuture simple implementation

考虑以下摘自 this article 的代码。为了学习目的,它实现了类似于 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) 之后被调用,留下线程永远停放。

这是真的吗?

是的。

LockSupport.park(this);

应该替换成类似

的东西
while (!waitingFuture.finished) {
    LockSupport.park(this);
}

一般来说,LockSupport.park 是一个太低的特征,为了可靠性,应该使用 Object::waitCondition::await

park()/unpark()不同于wait/notify,因为如果在[之前调用了unpark,信号不会丢失=10=].

然而,仍然只有一个位不计算 unpark 被调用的频率,因此假设所有调用都将完美配对仍然是错误的。

此外,park 将在中断时静默 return,甚至允许 return 虚假地 ,这意味着无缘无故。

换句话说,即使 return 从 park() 开始也不能保证条件已经满足。就像其他通知机制一样,无法在循环中使用它。

引用的代码更糟,因为它有另一个关于 thread 变量的竞争条件。不能保证它已经在另一个线程读取它以通知它的时候被写入。