理解 CompletableFuture 简单实现
Understanding CompletableFuture simple implementation
考虑以下摘自 this article 的代码。为了学习目的,它实现了类似于 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)
之后被调用,留下线程永远停放。
这是真的吗?
是的。
LockSupport.park(this);
应该替换成类似
的东西
while (!waitingFuture.finished) {
LockSupport.park(this);
}
一般来说,LockSupport.park 是一个太低的特征,为了可靠性,应该使用 Object::wait
或 Condition::await
。
park()
/unpark()
不同于wait
/notify
,因为如果在[之前调用了unpark
,信号不会丢失=10=].
然而,仍然只有一个位不计算 unpark
被调用的频率,因此假设所有调用都将完美配对仍然是错误的。
此外,park
将在中断时静默 return,甚至允许 return 虚假地 ,这意味着无缘无故。
换句话说,即使 return 从 park()
开始也不能保证条件已经满足。就像其他通知机制一样,无法在循环中使用它。
引用的代码更糟,因为它有另一个关于 thread
变量的竞争条件。不能保证它已经在另一个线程读取它以通知它的时候被写入。
考虑以下摘自 this article 的代码。为了学习目的,它实现了类似于 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)
之后被调用,留下线程永远停放。
这是真的吗?
是的。
LockSupport.park(this);
应该替换成类似
的东西while (!waitingFuture.finished) {
LockSupport.park(this);
}
一般来说,LockSupport.park 是一个太低的特征,为了可靠性,应该使用 Object::wait
或 Condition::await
。
park()
/unpark()
不同于wait
/notify
,因为如果在[之前调用了unpark
,信号不会丢失=10=].
然而,仍然只有一个位不计算 unpark
被调用的频率,因此假设所有调用都将完美配对仍然是错误的。
此外,park
将在中断时静默 return,甚至允许 return 虚假地 ,这意味着无缘无故。
换句话说,即使 return 从 park()
开始也不能保证条件已经满足。就像其他通知机制一样,无法在循环中使用它。
引用的代码更糟,因为它有另一个关于 thread
变量的竞争条件。不能保证它已经在另一个线程读取它以通知它的时候被写入。