释放未来

时间:2016-06-01 00:55:19

标签: java future race-condition

我正在创建一个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不是为了处理而设计的,我们应该避免使用它?

1 个答案:

答案 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;
        }
    }

}