2012-04-18 58 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

相關問題