它是用java.util.concurrent.FutureTask中的好办法?
-
22-08-2019 - |
题
首先,我必须说,我很新的API的java.util.concurrent,所以也许我做的是完全错误的。
什么我想要做什么?
我有基本上运行2个独立的处理的Java应用程序(称为 myFirstProcess , mySecondProcess ),但这些处理,必须在同一时间运行。
所以,我想这样做:
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
...
}
myFirstProcess 和 mySecondProcess 是实现Callable<Object>
类,并且其中所有的处理是在呼叫()方法进行说明。
这是合作得非常好,但我不知道它是做正确的方式。 是做我想做什么好办法?如果没有,你可以给我一些提示,以提高我的代码(现在仍然保持尽可能简单)。
解决方案
您会更好使用get()
方法。
futureOne.get();
futureTwo.get();
这两者等待来自线程,它完成处理的通知,这可以节省的忙等待与 - 计时器您现在使用效率不高也不优雅。
作为奖励,你有API get(long timeout, TimeUnit unit)
它允许你定义一个最大时间的线程休眠和等待响应,否则继续运行。
请参阅更多信息的Java API 。
其他提示
以上FutureTask
的用途是容许的,但绝对不惯用。你实际上是一个包装的额外的的在你身边提交FutureTask
的一个ExecutorService
。你FutureTask
被视为由Runnable
一个ExecutorService
。在内部,它包你FutureTask
-AS-Runnable
在新FutureTask
并返回给你作为一个Future<?>
。
相反,你应该提交您的Callable<Object>
实例到的 CompletionService
。你可以通过Callable
顺路2个submit(Callable<V>)
s,然后转身和呼叫CompletionService#take()
两次(一次为每个提交Callable
)。这些调用将阻塞,直到一个,然后其他提交的任务已经完成。
既然你已经在手的Executor
,构建一个新的周围ExecutorCompletionService
,并在那里放下你的任务。不要旋转和睡眠等待; CompletionService#take()
将阻塞,直到任一的你的任务之一是完全的(无论是完成运行或取消)或线程等待take()
被中断。
尤瓦的解决方案是细。作为替代方案也可以做到这一点:
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
}
什么是这种方法的优势在哪里?这里没有很大的差异真的只是这样,你停止执行接受任何更多的任务(你可以做到这一点的其他方式)。我倾向于选择这个成语一个虽然。
此外,如果要么得到()抛出一个异常,你可以在你的代码的一部分,它假定这两个任务都做了,这可能是坏的结束。
可以使用的invokeAll(集合....)方法
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获得更多信息。
如果您futureTasks是超过2,请考虑[ListenableFuture][1]
。
当的若干操作应尽快开始作为另一操作 开始 - “扇出” - ListenableFuture只是工作:它触发所有的 所请求的回调。具有稍微更多的工作,我们可以通过“的扇入下,”或 触发ListenableFuture得到尽快计算出其他几个 期货已经全部完成。