0

我有一个多线程执行,我想跟踪并打印出执行时间,但是当我执行代码时,子线程比主执行花费更长的时间,因此输出不可见,也不会打印正确的值,因为它是提前终止。

这是代码:

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(超时,TimeUnit.SECONDS);

实际上执行器服务从不执行线程。

哪个可以是仅在 ExecutorService 块中执行多线程并在最后完成主要执行的解决方案?

4

2 回答 2

1

ExecutorService#submit()方法返回一个Future对象,该对象可用于等待提交的任务完成。

这个想法是你收集所有这些Futures,然后调用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...
于 2012-04-18T00:35:52.247 回答
1

鉴于您的用户案例,您不妨使用该invokeAll方法。来自 Javadoc:

执行给定的任务,返回一个 Futures 列表,在所有完成时保存它们的状态和结果。Future.isDone() 对于返回列表的每个元素都是 true。请注意,已完成的任务可能已经正常终止,也可能通过引发异常终止。如果在此操作进行时修改了给定的集合,则此方法的结果是不确定的。

要使用:

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,以验证已完成任务的状态。

祝你好运。

于 2012-04-18T00:41:03.873 回答