这是使用java.util.concurrent.FutureTask的好方法吗?

首先,我必须说我对API java.util.concurrent很陌生,所以也许我所做的是完全错误的。

我想做什么?

我有一个基本上运行2个独立处理(称为myFirstProcessmySecondProcess )的Java应用程序,但是这些处理必须同时运行。

所以,我试图这样做:

public void startMyApplication() { ExecutorService executor = Executors.newFixedThreadPool(2); FutureTask<Object> futureOne = new FutureTask<Object>(myFirstProcess); FutureTask<Object> futureTwo = new FutureTask<Object>(mySecondProcess); executor.execute(futureOne); executor.execute(futureTwo); while (!(futureOne.isDone() && futureTwo.isDone())) { try { // I wait until both processes are finished. Thread.sleep(1000); } catch (InterruptedException e) { e.printStackTrace(); } } logger.info("Processing finished"); executor.shutdown(); // Do some processing on results ... } 

myFirstProcessmySecondProcess是实现Callable<Object> ,并且在call()方法中完成所有处理。

它工作得很好,但我不确定这是否正确。 做我想要的是一个好方法吗? 如果没有,你可以给我一些提示,以提高我的代码(并保持尽可能简单)。

你最好使用get()方法。

 futureOne.get(); futureTwo.get(); 

两者都等待线程完成处理的通知,这样可以节省您正在使用的busy-wait-with-timer,效率和优雅性都不高。

作为奖励,你有API get(long timeout, TimeUnit unit) ,它允许你定义线程hibernate的最大时间并等待响应,否则继续运行。

有关更多信息,请参阅Java API 。

以上FutureTask的使用是可以忍受的,但绝对不是惯用的。 实际上,您将一个额外的 FutureTask包装在您提交给ExecutorService那个FutureTask附近。 您的FutureTaskExecutorService视为Runnable 。 在内部,它将FutureTask -as- Runnable包装在一个新的FutureTask ,并将其作为Future<?>返回给您。

相反,您应该将您的Callable<Object>实例提交给CompletionService 。 您可以通过submit(Callable<V>)放弃两个Callable s,然后转身并调用CompletionService#take()两次(每个提交的Callable一次)。 这些呼叫将阻塞,直到一个,然后提交的其他任务完成。

考虑到你已经有一个Executor了,围绕它构造一个新的ExecutorCompletionService ,并把你的任务放在那里。 不要旋转和睡觉等待; CompletionService#take()将会阻塞,直到任一个任务完成(或者完成运行或取消)或者等待take()的线程中断。

Yuval的解决scheme是好的。 作为一种select,你也可以这样做:

 ExecutorService executor = Executors.newFixedThreadPool(); FutureTask<Object> futureOne = new FutureTask<Object>(myFirstProcess); FutureTask<Object> futureTwo = new FutureTask<Object>(mySecondProcess); executor.execute(futureOne); executor.execute(futureTwo); executor.shutdown(); try { executor.awaitTermination(Long.MAX_VALUE, TimeUnit.NANOSECONDS); } catch (InterruptedException e) { // interrupted } 

这种方法的优点是什么? 除了这种方式,你可以阻止执行者接受更多的任务(你也可以这样做),除此之外没有什么区别。 我倾向于喜欢这个成语。

另外,如果get()抛出一个exception,你最终可能会在你的代码的一部分,假定这两个任务完成,这可能是不好的。

你可以使用invokeall(Colelction ….)方法

 package concurrent.threadPool; import java.util.Arrays; import java.util.List; import java.util.concurrent.Callable; import java.util.concurrent.ExecutionException; import java.util.concurrent.ExecutorService; import java.util.concurrent.Executors; import java.util.concurrent.Future; public class InvokeAll { public static void main(String[] args) throws Exception { ExecutorService service = Executors.newFixedThreadPool(5); List<Future<java.lang.String>> futureList = service.invokeAll(Arrays.asList(new Task1<String>(),new Task2<String>())); System.out.println(futureList.get(1).get()); System.out.println(futureList.get(0).get()); } private static class Task1<String> implements Callable<String>{ @Override public String call() throws Exception { Thread.sleep(1000 * 10); return (String) "1000 * 5"; } } private static class Task2<String> implements Callable<String>{ @Override public String call() throws Exception { Thread.sleep(1000 * 2); int i=3; if(i==3) throw new RuntimeException("Its Wrong"); return (String) "1000 * 2"; } } } 

如果您有兴趣同时启动线程,或等待它们完成,然后再做一些处理,则可能需要使用CyclicBarrier 。 有关更多信息,请参阅javadoc。

如果您的未来任务超过2,请考虑[ListenableFuture][1]

当另一个操作开始时,几个操作应该开始 – “ 扇出 ” – ListenableFuture只是起作用:触发所有请求的callback。 只要稍微做些工作,我们就可以“煽风点火”,或者其他几个期货全部完成的情况下立刻触发ListenableFuture。