本篇主要涉及到的是java
.util.concurrent包中的ExecutorService。ExecutorService就是Java中對線程池的實現。
1、ExecutorService介紹
ExecutorService是Java中對線程池定義的一個接口,它java.util.concurrent
包中,在這個接口中定義了和後臺任務執行相關的方法:
java
Java API對ExecutorService接口的實現有兩個,因此這兩個便是Java線程池具體實現類(詳細瞭解這兩個實現類,點擊這裏):緩存
1. ThreadPoolExecutor
2. ScheduledThreadPoolExecutor
除此以外,ExecutorService還繼承了Executor
接口(注意區分Executor接口和Executors工廠類),這個接口只有一個execute()
方法,最後咱們看一下整個繼承樹:
markdown
2、ExecutorService的建立
建立一個什麼樣的ExecutorService的實例(即線程池)須要g根據具體應用場景而定,不過Java給咱們提供了一個Executors工廠類
,它能夠幫助咱們很方便的建立各類類型ExecutorService線程池,Executors一共能夠建立下面這四類線程池:併發
1. newCachedThreadPool 建立一個可緩存線程池,若是線程池長度超過處理須要,可靈活回收空閒線程,若無可回收,則新建線程。
2. newFixedThreadPool 建立一個定長線程池,可控制線程最大併發數,超出的線程會在隊列中等待。
3. newScheduledThreadPool 建立一個定長線程池,支持定時及週期性任務執行。
4. newSingleThreadExecutor 建立一個單線程化的線程池,它只會用惟一的工做線程來執行任務,保證全部任務按照指定順序(FIFO, LIFO, 優先級)執行。
備註:Executors只是一個工廠類,它全部的方法返回的都是ThreadPoolExecutor
、ScheduledThreadPoolExecutor
這兩個類的實例。異步
3、ExecutorService的使用
ExecutorService executorService = Executors.newFixedThreadPool(
10);
executorService.execute(
new Runnable() {
public void run() {
System.
out.println(
"Asynchronous task");
}
});
executorService.shutdown();
4、ExecutorService的執行
ExecutorService有以下幾個執行方法:ui
- execute(Runnable)
- submit(Runnable)
- submit(Callable)
- invokeAny(
...)
- invokeAll(
...)
4.1 execute(Runnable)
這個方法接收一個Runnable實例,而且異步的執行,請看下面的實例:spa
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對象,咱們能夠檢查提交的任務是否執行完畢,請看下面執行的例子:線程
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
的,沒有返回值。請看下面實例:
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工廠類更詳細介紹,點擊這裏