Java線程池 ExecutorService

    

    

    
    
    
    
    
    
  • 1
  • 2
本篇主要涉及到的是java.util.concurrent包中的ExecutorService。ExecutorService就是Java中對線程池的實現。

1、ExecutorService介紹

ExecutorService是Java中對線程池定義的一個接口,它java.util.concurrent包中,在這個接口中定義了和後臺任務執行相關的方法:
這裏寫圖片描述java

Java API對ExecutorService接口的實現有兩個,因此這兩個便是Java線程池具體實現類(詳細瞭解這兩個實現類,點擊這裏):緩存

    

    

    
    
    
    
    
    
  • 1
  • 2
  • 3
1. ThreadPoolExecutor 2. ScheduledThreadPoolExecutor

除此以外,ExecutorService還繼承了Executor接口(注意區分Executor接口和Executors工廠類),這個接口只有一個execute()方法,最後咱們看一下整個繼承樹:
這裏寫圖片描述markdown

2、ExecutorService的建立

建立一個什麼樣的ExecutorService的實例(即線程池)須要g根據具體應用場景而定,不過Java給咱們提供了一個Executors工廠類,它能夠幫助咱們很方便的建立各類類型ExecutorService線程池,Executors一共能夠建立下面這四類線程池:併發

    

    

    
    
    
    
    
    
  • 1
  • 2
  • 3
  • 4
  • 5
1. newCachedThreadPool 建立一個可緩存線程池,若是線程池長度超過處理須要,可靈活回收空閒線程,若無可回收,則新建線程。 2. newFixedThreadPool 建立一個定長線程池,可控制線程最大併發數,超出的線程會在隊列中等待。 3. newScheduledThreadPool 建立一個定長線程池,支持定時及週期性任務執行。 4. newSingleThreadExecutor 建立一個單線程化的線程池,它只會用惟一的工做線程來執行任務,保證全部任務按照指定順序(FIFO, LIFO, 優先級)執行。

備註:Executors只是一個工廠類,它全部的方法返回的都是ThreadPoolExecutorScheduledThreadPoolExecutor這兩個類的實例。異步

3、ExecutorService的使用

    

    

    
    
    
    
    
    
  • 1
  • 2
  • 3
  • 4
  • 5
  • 6
  • 7
  • 8
  • 9
  • 10
ExecutorService executorService = Executors.newFixedThreadPool(10); executorService.execute(new Runnable() { public void run() { System.out.println("Asynchronous task"); } }); executorService.shutdown();

4、ExecutorService的執行

ExecutorService有以下幾個執行方法:ui

    

    

    
    
    
    
    
    
  • 1
  • 2
  • 3
  • 4
  • 5
  • 6
- execute(Runnable) - submit(Runnable) - submit(Callable) - invokeAny(...) - invokeAll(...)

4.1 execute(Runnable)

這個方法接收一個Runnable實例,而且異步的執行,請看下面的實例:spa

    

    

    
    
    
    
    
    
  • 1
  • 2
  • 3
  • 4
  • 5
  • 6
  • 7
  • 8
  • 9
  • 10
ExecutorService executorService = Executors.newSingleThreadExecutor(); executorService.execute(new Runnable() { public void run() { System.out.println("Asynchronous task"); } }); executorService.shutdown();

這個方法有個問題,就是沒有辦法獲知task的執行結果。若是咱們想得到task的執行結果,咱們能夠傳入一個Callable的實例(下面會介紹)。.net

4.2 submit(Runnable)

submit(Runnable)execute(Runnable)區別是前者能夠返回一個Future對象,經過返回的Future對象,咱們能夠檢查提交的任務是否執行完畢,請看下面執行的例子:線程

    

    

    
    
    
    
    
    
  • 1
  • 2
  • 3
  • 4
  • 5
  • 6
  • 7
  • 8
Future future = executorService.submit(new Runnable() { public void run() { System.out.println("Asynchronous task"); } }); future.get(); //returns null if the task has finished correctly.

若是任務執行完成,future.get()方法會返回一個null。注意,future.get()方法會產生阻塞。code

4.3 submit(Callable)

submit(Callable)submit(Runnable)相似,也會返回一個Future對象,可是除此以外,submit(Callable)接收的是一個Callable的實現,Callable接口中的call()方法有一個返回值,能夠返回任務的執行結果,而Runnable接口中的run()方法是void的,沒有返回值。請看下面實例:

    

    

    
    
    
    
    
    
  • 1
  • 2
  • 3
  • 4
  • 5
  • 6
  • 7
  • 8
  • 9
Future future = executorService.submit(new Callable(){ public Object call() throws Exception { System.out.println("Asynchronous Callable"); return "Callable Result"; } }); System.out.println("future.get() = " + future.get());

若是任務執行完成,future.get()方法會返回Callable任務的執行結果。注意,future.get()方法會產生阻塞。

4.4 invokeAny(…)

invokeAny(...)方法接收的是一個Callable的集合,執行這個方法不會返回Future,可是會返回全部Callable任務中其中一個任務的執行結果。這個方法也沒法保證返回的是哪一個任務的執行結果,反正是其中的某一個。請看下面實例:

    

    

    
    
    
    
    
    
  • 1
  • 2
  • 3
  • 4
  • 5
  • 6
  • 7
  • 8
  • 9
  • 10
  • 11
  • 12
  • 13
  • 14
  • 15
  • 16
  • 17
  • 18
  • 19
  • 20
  • 21
  • 22
  • 23
  • 24
ExecutorService executorService = Executors.newSingleThreadExecutor(); Set<Callable<String>> callables = new HashSet<Callable<String>>(); callables.add(new Callable<String>() { public String call() throws Exception { return "Task 1"; } }); callables.add(new Callable<String>() { public String call() throws Exception { return "Task 2"; } }); callables.add(new Callable<String>() { public String call() throws Exception { return "Task 3"; } }); String result = executorService.invokeAny(callables); System.out.println("result = " + result); executorService.shutdown();

你們能夠嘗試執行上面代碼,每次執行都會返回一個結果,而且返回的結果是變化的,可能會返回「Task2」也但是「Task1」或者其它。

4.5 invokeAll(…)

invokeAll(...)invokeAny(...)相似也是接收一個Callable集合,可是前者執行以後會返回一個Future的List,其中對應着每一個Callable任務執行後的Future對象。狀況下面這個實例:

    

    

    
    
    
    
    
    
  • 1
  • 2
  • 3
  • 4
  • 5
  • 6
  • 7
  • 8
  • 9
  • 10
  • 11
  • 12
  • 13
  • 14
  • 15
  • 16
  • 17
  • 18
  • 19
  • 20
  • 21
  • 22
  • 23
  • 24
  • 25
  • 26
  • 27
  • 28
ExecutorService executorService = Executors.newSingleThreadExecutor(); Set<Callable<String>> callables = new HashSet<Callable<String>>(); callables.add(new Callable<String>() { public String call() throws Exception { return "Task 1"; } }); callables.add(new Callable<String>() { public String call() throws Exception { return "Task 2"; } }); callables.add(new Callable<String>() { public String call() throws Exception { return "Task 3"; } }); List<Future<String>> futures = executorService.invokeAll(callables); for(Future<String> future : futures){ System.out.println("future.get = " + future.get()); } executorService.shutdown();

5、ExecutorService的關閉

當咱們使用完成ExecutorService以後應該關閉它,不然它裏面的線程會一直處於運行狀態。

舉個例子,若是的應用程序是經過main()方法啓動的,在這個main()退出以後,若是應用程序中的ExecutorService沒有關閉,這個應用將一直運行。之因此會出現這種狀況,是由於ExecutorService中運行的線程會阻止JVM關閉。

若是要關閉ExecutorService中執行的線程,咱們能夠調用ExecutorService.shutdown()方法。在調用shutdown()方法以後,ExecutorService不會當即關閉,可是它再也不接收新的任務,直到當前全部線程執行完成纔會關閉,全部在shutdown()執行以前提交的任務都會被執行。

若是咱們想當即關閉ExecutorService,咱們能夠調用ExecutorService.shutdownNow()方法。這個動做將跳過全部正在執行的任務和被提交尚未執行的任務。可是它並不對正在執行的任務作任何保證,有可能它們都會中止,也有可能執行完成。


關於Java線程池類ThreadPoolExecutor、ScheduledThreadPoolExecutor及Executors工廠類更詳細介紹,點擊這裏

相關文章
相關標籤/搜索