我正在创建一个API,为客户提供他们需要明确发布的资源(la Closeable.close()
)vi a Future
。这种模式对我们的用例有很多不错的功能,但它带有一个皱纹。如果客户端决定他们不再需要资源,他们可以调用Future.cancel(true)
来取消(可能很昂贵的)分配。然而,这引入了竞争条件;如果资源在实际调用.cancel()
之前完成分配,则未来实际上不会释放资源。
以下是一个例子:
Future<Resource> resource = service.requestResource();
try {
doSomething(resource.get(1, TimeUnit.MINUTES));
} catch (TimeoutException e) {
// by this point resource could be done, and .cancel() will be a no-op
resource.cancel(true);
}
似乎“正确”的做法是让客户在调用取消后总是尝试释放资源,例如:
if (!resource.cancel(true)) {
resource.get().close();
}
但这似乎很容易被客户滥用。一种选择是使用ForwardingFuture
并使用这种近似行为来装饰.cancel()
,但这似乎违反了.cancel()
“will fail if the task has already completed”的合同
如果任务完成,必须Future.cancel()
禁止操作吗?是否有更好的模式以较少出错的方式解决这种竞争条件?或者这只是Future
不是为了处理而设计的,我们应该避免使用它?
答案 0 :(得分:0)
假设您可以期望您的客户至少打电话取消,只需通过自己实施来做正确的事情:
public class CloseableFuture<V extends Closeable> extends FutureTask<V> {
@Override
public boolean cancel(boolean mayInterruptIfRunning) {
if (!super.cancel(true)) {
// Handle exception
get().close();
return false;
}
else {
return true;
}
}
}