我有一个多线程执行,我想跟踪并打印执行时间,但是当我执行代码时,子线程比主执行花费的时间更长,因此输出不可见,也没有打印正确的值,因为它提前结束了。
以下是代码:
public static void main(String[] args) throws CorruptIndexException, IOException, LangDetectException, InterruptedException {
/* Initialization */
long startingTime = System.currentTimeMillis();
Indexer main = new Indexer(); // this class extends Thread
File file = new File(SITES_PATH);
main.addFiles(file);
/* Multithreading through ExecutorService */
ExecutorService es = Executors.newFixedThreadPool(4);
for (File f : main.queue) {
Indexer ind = new Indexer(main.writer, main.identificatore, f);
ind.join();
es.submit(ind);
}
es.shutdown();
/* log creation - code I want to execute when all the threads execution ended */
long executionTime = System.currentTimeMillis()-startingTime;
long minutes = TimeUnit.MILLISECONDS.toMinutes(executionTime);
long seconds = TimeUnit.MILLISECONDS.toSeconds(executionTime)%60;
String fileSize = sizeConversion(FileUtils.sizeOf(file));
Object[] array = {fileSize,minutes,seconds};
logger.info("{} indexed in {} minutes and {} seconds.",array);
}
我尝试了几个解决方案,例如join(),wait()和notifyAll(),但没有一个解决方案。
我在stackoverflow上找到了Q&A来处理我的问题,但是如果我把
放入了join()es.awaitTermination(timeout,TimeUnit.SECONDS);
实际上,执行程序服务从不执行线程。
哪个可以是仅在ExecutorService块中执行多线程的解决方案,并在最后执行主执行?
答案 0 :(得分:1)
ExecutorService#submit()
方法返回一个Future
对象,可用于等待提交的任务完成。
您的想法是收集所有这些Future
,然后在每个get()
上调用ExecutorService es = Executors.newFixedThreadPool(4);
List<Future<?>> futures = new ArrayList<Future<?>>();
for (File f : main.queue) {
Indexer ind = new Indexer(main.writer, main.identificatore, f);
ind.join();
Future<?> future = es.submit(ind);
futures.add(future);
}
// wait for all tasks to complete
for (Future<?> f : futures) {
f.get();
}
// shutdown thread pool, carry on working in main thread...
。这可确保在主线程继续之前完成所有已提交的任务。
这样的事情:
{{1}}
答案 1 :(得分:1)
根据您的用户案例,您也可以使用invokeAll
方法。来自Javadoc:
执行给定的任务,返回持有他们的期货清单 完成后的状态和结果。 Future.isDone()对每个都是正确的 返回列表的元素。请注意,已完成的任务可能具有 正常终止或通过抛出异常终止。结果 如果同时修改给定集合,则此方法未定义 此操作正在进行中。
使用:
final Collection<Indexer> tasks = new ArrayList<Indexer>();
for(final File f: main.queue) {
tasks.add(new Indexer(main.writer, main.identificatore, f));
}
final ExecutorService es = Executors.newFixedThreadPool(4);
final List<Future<Object>> results = es.invokeAll(tasks);
这将执行所有提供的任务并等待它们完成处理,然后继续主线程。您需要调整代码以满足您的特定需求,但您可以获得要点。快速说明,有invokeAll
方法的变体接受超时参数。如果要在继续之前等待最长时间,请使用该变体。并确保在invokeAll
完成后检查收集的结果,以验证已完成任务的状态。