Java中如何通过CompletionService的poll方法确定哪个Callable已完成
能不能确定CompletionService返回的Future对应哪个Callable?
答案是默认情况下不行——标准的Future接口并没有提供方法让你直接关联回提交的Callable实例,CompletionService的poll()/take()也只会返回完成的Future,没有额外的关联信息。
不过我们可以通过包装Callable的方式解决这个问题,核心思路是把原始Callable和你需要的标识(或者Callable本身)绑定在一起,提交包装后的任务,这样当Future完成时,就能拿到关联的信息。
举个具体的例子:
首先定义一个包装类,用来包裹原始Callable和它的标识(或者直接保存Callable):
class WrapperCallable<T> implements Callable<WrapperResult<T>> { private final Callable<T> originalCallable; private final String taskId; // 或者直接保存originalCallable本身 public WrapperCallable(Callable<T> originalCallable, String taskId) { this.originalCallable = originalCallable; this.taskId = taskId; } @Override public WrapperResult<T> call() throws Exception { T result = originalCallable.call(); return new WrapperResult<>(taskId, originalCallable, result); } } // 用来保存结果和关联信息的类 class WrapperResult<T> { private final String taskId; private final Callable<T> originalCallable; private final T result; public WrapperResult(String taskId, Callable<T> originalCallable, T result) { this.taskId = taskId; this.originalCallable = originalCallable; this.result = result; } // getter方法 public String getTaskId() { return taskId; } public Callable<T> getOriginalCallable() { return originalCallable; } public T getResult() { return result; } }
然后修改你的提交逻辑:
CompletionService<WrapperResult<T>> completion = new ExecutorCompletionService<>(executorService); int taskIndex = 0; for(Callable<T> callable : callableList) { // 给每个任务加个标识,或者直接传callable本身 completion.submit(new WrapperCallable<>(callable, "Task-" + taskIndex++)); } // 执行其他操作 while(true) { Future<WrapperResult<T>> future = completion.poll(); if (future == null) { // 没有完成的任务,可根据情况退出循环 break; } try { WrapperResult<T> wrapperResult = future.get(); // 这里就能拿到对应的原始Callable或者任务标识了 System.out.println("完成的任务ID: " + wrapperResult.getTaskId()); System.out.println("对应的Callable实例: " + wrapperResult.getOriginalCallable()); T actualResult = wrapperResult.getResult(); // 处理实际结果 } catch (Exception e) { // 处理异常 } }
这样就能轻松关联回每个完成的Future对应的原始Callable了。本质上是通过包装任务,把关联信息嵌入到任务的返回结果中,因为Future的get()方法会返回任务执行的结果,我们自然就能拿到绑定的信息。
内容的提问来源于stack exchange,提问作者jaeyong
相关产品推荐
相关产品推荐

