2016-03-17 45 views
1

我正在嘗試編寫一個程序,它將在多個Java工作線程中劃分工作。問題是,當我從命令行運行它時,它永遠不會返回。我沒有得到我的提示,最終必須按ctrl-c關閉程序。使用ExecutorService的Java應用程序永遠不會關閉

我它簡化爲以下瑣碎的情況下

import java.util.concurrent.Callable; 
import java.util.concurrent.ExecutorService; 
import java.util.concurrent.Executors; 
import java.util.concurrent.Future; 

public class TestExeServ { 

    private class ExpensiveTask implements Callable<Integer>{ 
     private final String msg; 
     public ExpensiveTask(String str){ 
      this.msg = str; 
     } 

     @Override 
     public Integer call() { 
      System.out.println("My message was " + msg); 
      return 1; 
     } 
    } 

    private void run() 
    { 
     final ExecutorService exeServ = Executors.newFixedThreadPool(2); 
     Future<Integer> result = exeServ.submit(new ExpensiveTask("Hello!")); 
     try { 
      System.out.println(" Task is done, it returned " + result.get()); 
     } catch (Exception e) { 
      e.printStackTrace(); 
     } 
    } 

    public static void main(String args[]) 
    { 
     System.out.println("Start");  

     TestExeServ tes = new TestExeServ(); 
     tes.run(); 
     System.out.println("Done"); 
    }  
} 

這個程序的輸出是

[email protected]:/local/mnt/workspace/TestExeServ/bin$ java TestExeServ 
    Start 
    my message was Hello! 
    Task is done, it returned 1 
    done 

就是這樣。它掛在那裏。沒有提示。如果我刪除ExecutorService.submit行,我得到

[email protected]:/local/mnt/workspace/TestExeServ/bin$ java TestExeServ 
    Start 
    done 
    [email protected]:/local/mnt/workspace/TestExeServ/bin$ 

程序自然關閉。

是否有一些清理任務需要在ExecutorService上執行,我做得不好?我假設.get()調用加入了線程。情況並非如此嗎?

+2

您需要關閉執行程序 –

+1

或者使用生成守護程序線程的線程工廠。 – assylias

+2

或設置標誌allowCoreThreadTimeout [ThreadPoolExecutor應用程序沒有完成](http://stackoverflow.com/q/30633698/217324) –

回答

5

您必須致電ExecutorService#shutdown()ExecutorService#shutdownNow()來終止執行程序的線程池。否則線程將保持活動狀態,從而阻止JVM終止。

ExecutorService類的Javadoc:

一個ExecutorService可以被關閉,這將導致其拒絕新任務。爲關閉ExecutorService提供了兩種不同的方法。 shutdown()方法將允許之前提交的任務在終止前執行,而shutdownNow()方法阻止等待任務啓動並嘗試停止當前正在執行的任務。終止時,執行者沒有主動執行的任務,沒有任務等待執行,也不能提交新的任務。

需要注意的是,作爲最後的手段,在ThreadPoolExecutor您使用會自行關閉時,它的垃圾收集 - 其finalize()方法調用shutdown()。但是,最好不要依賴這個並明確關閉執行程序。


由於@mre在註釋中說,我會讓它明確 - 你可以安全地只需撥打exeServ.shutdown()run()方法結束,因爲Future.get()會阻塞,因此,當代碼執行後get()你不要再需要執行者了。但是,如果這是更復雜的真實場景的簡化版本,則可能需要找到合適的地方以安全地撥打shutdown()

+0

而'shutdownNow'可以,因爲'result.get'將會阻塞,直到任務完成,否則你冒着取消它的風險。 – mre

相關問題