2012-04-18 59 views
0

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

下面是代码:

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); 
} 

我尝试了几种解决方案,比如加入(),wait()和notifyAll的(),但没有一次成功。

我发现这个计算器其中Q&A对待我的问题,但join()方法将被忽略,如果我把

es.awaitTermination(超时,TimeUnit.SECONDS);

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

哪一种解决方案只能在ExecutorService块中执行多线程,并在最后执行主执行?

+0

我只需将'Runnable'提交给'ExecutorService',而不是调用'join()'或其他任何东西。您使用并发框架的方式似乎不正确。还要注意生成的线程是用户线程:守护进程线程不会阻止JVM退出。我很确定,默认情况下,线程是用户线程。 – 2012-04-18 02:50:53

回答

1

鉴于你的用户情况下,你不妨利用invokeAll方法。根据JavaDoc:

执行给定的任务,返回的Future列表拿着自己 状态和结果当所有完成。 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完成后收集的结果,以验证已完成任务的状态。

祝你好运。

1

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

这个想法是,你收集所有这些Future s,然后打电话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... 
+0

非常感谢!它现在运作良好! – Tsuneo 2012-04-18 11:38:24

相关问题