Java执行程序:等待任务终止。
我需要提交一些任务,然后等待所有结果,直到所有结果都可用。 它们中的每一个都向Vector
添加一个String
(默认情况下是同步的)。 然后我需要为Vector中的每个结果启动一个新任务,但是只有当所有先前的任务都停止完成它们的工作时我才需要这样做。
我想使用Java Executor,特别是我尝试使用Executors.newFixedThreadPool(100)
来使用固定数量的线程(我有一个可变数量的任务,可以是10或500)但我是执行器和我不知道如何等待任务终止。 这就像我的程序需要做的伪代码:
ExecutorService e = Executors.newFixedThreadPool(100); while(true){ /*do something*/ for(...){ } for each String in result{ } }
我不能做e.shutdown,因为我有一段时间(真的)我需要重用executorService
…
你能帮助我吗? 你能给我一个关于java执行器的指南/书吗?
ExecutorService
为您提供了一种机制,可以同时执行多个任务并获取Future
对象的集合(表示任务的异步计算)。
Collection> tasks = new LinkedList>(); //populate tasks for (Future> f : executorService.invokeAll(tasks)) { //invokeAll() blocks until ALL tasks submitted to executor complete f.get(); }
如果你有Runnable
而不是Callable
,你可以使用以下方法轻松地将Runnable
转换为Callable
:
Callable> c = Executors.callable(runnable);
而不是直接向Executor
提交Runnable
或Callable
,并存储相应的Future
返回值,我建议使用CompletionService
实现在CompletionService
时检索每个Future
。 这种方法将任务的产生与已完成任务的消耗分离,允许例如在一段时间内在生产者线程上发起新任务。
Collection> workItems = ... ExecutorService executor = Executors.newSingleThreadExecutor(); CompletionService compService = new ExecutorCompletionService (executor); // Add work items to Executor. for (Callable workItem : workItems) { compService.submit(workItem); } // Consume results as they complete (this would typically occur on a different thread). for (int i=0; i fut = compService.take(); // Will block until a result is available. Result result = fut.get(); // Extract result; this will not block. }
你能给我一个关于java执行器的指南/书吗?
我可以回答这一部分:
Brian Goetz的实践中的Java Concurrency (与Tim Peierls, Joshua Bloch ,Joseph Bowbeer,David Holmes和Doug Lea一起 )很可能是你最好的选择。
它不仅仅是关于执行程序,而是涵盖了一般的java.util.concurrent
包,以及基本的并发概念和技术,以及一些高级主题,如Java内存模型。
当您提交执行程序服务时,您将获得Future对象。
将这些对象存储在集合中,然后依次对每个对象调用get() 。 get()
阻塞直到底层作业完成,因此结果是,一旦所有基础作业完成,就会在每个作业上调用get()
。
例如
Collection futures = ... for (Future f : futures) { Object result = f.get(); // maybe do something with the result. This could be a // genericised Future } System.out.println("Tasks completed");
完成所有这些后,再开始第二次提交。 请注意,这可能不是您的线程池的最佳使用,因为它将变为hibernate状态,然后您将重新填充它。 如果可能的话,试着让它忙着做事。
ExecutorService executor = ... //submit tasks executor.shutdown(); // previously submitted tasks are executed, // but no new tasks will be accepted while(!executor.awaitTermination(1, TimeUnit.SECONDS)) ;
没有创建自定义ExecutorService,没有简单的方法可以做你想做的事情。