TL;DR:虽然可能有一些侵入性的方式(即反射),但Future
该方法返回的ExecutionCompletionService.poll()
并不会暴露Callable
已完成的内容。
查看 JDK 9 的源代码ExecutionCompletionService.submit(Callable)
,提交Callable
的内容包含在 a 中(如果我们查看RunnableFuture
,其实际类型是):FutureTask
newTaskFor(Callable)
public Future<V> submit(Callable<V> task) {
if (task == null) throw new NullPointerException();
RunnableFuture<V> f = newTaskFor(task);
executor.execute(new QueueingFuture<V>(f, completionQueue));
return f;
}
private RunnableFuture<V> newTaskFor(Callable<V> task) {
if (aes == null)
return new FutureTask<V>(task);
else
return aes.newTaskFor(task);
}
即使aes.newTaskFor(task)
被调用, whereaes
是 a AbstractExecutorService
,结果也是 a FutureTask
:
public abstract class AbstractExecutorService implements ExecutorService {
// ...
protected <T> RunnableFuture<T> newTaskFor(Callable<T> callable) {
return new FutureTask<T>(callable);
}
}
如果我们查看QueueingFuture
内部类,我们会看到以下定义:
private static class QueueingFuture<V> extends FutureTask<Void> {
QueueingFuture(RunnableFuture<V> task,
BlockingQueue<Future<V>> completionQueue) {
super(task, null);
this.task = task;
this.completionQueue = completionQueue;
}
private final Future<V> task;
private final BlockingQueue<Future<V>> completionQueue;
protected void done() { completionQueue.add(task); }
}
completionQueue
传递给方法中新创建QueueingFuture
的是submit
a BlockingQueue<Future<T>>
,它存储与提供给 的已完成对象Future
相对应的对象。换句话说,一旦一个提交到使用该方法完成执行,对应于该提交的 将被排入. 该方法简单地委托给一个民意调查:Callable
submit
Callable
ExecutorCompletionService
submit
Future
Callable
completionQueue
ExecutionCompletionService.poll()
completionQueue
public Future<V> poll() {
return completionQueue.poll();
}
因此,我们可以获得对原始对象的引用的唯一方法是从(您的原始问题)返回的对象Callable
中获取它。但是,查看接口,不存在公开任何方法的方法:Future
ExecutionCompletionService.poll()
Future
Callable
public interface Future<V> {
boolean cancel(boolean mayInterruptIfRunning);
boolean isCancelled();
boolean isDone();
V get() throws InterruptedException, ExecutionException;
V get(long timeout, TimeUnit unit)
throws InterruptedException, ExecutionException, TimeoutException;
}
甚至FutureTask
(从返回的实现类型ExecutionCompletionService.poll()
)也不会暴露其内部Callable
:
public class FutureTask<V> implements RunnableFuture<V> {
private Callable<V> callable;
public FutureTask(Callable<V> callable) {
if (callable == null)
throw new NullPointerException();
this.callable = callable;
// ...
}
}
如果FutureTask
有一些暴露底层的方法Callable
,那么我们也许可以对 进行显式转换FutureTask
,但既然没有,那么该路由将无法解决手头的问题。
这里的问题是我们正在尝试将同步代码与异步代码结合起来ExecutionCompletionService
。以同步方式解决此问题的一种方法是在Callable
完成时返回 ID,以便调用返回Future.get()
的Future
fromExecutionCompletionService.poll()
返回 ID(如您所述)。然后可以将 ID 与其原始 ID 配对Callable
。异步方法是使用完成Callable
时调用的原始回调注册回调Callable
。
希望解释比简单的no更有帮助。