深入java線程池的使用詳解
更新時(shí)間:2013年05月16日 17:54:29 作者:
本篇文章是對java線程池的使用進(jìn)行了詳細(xì)的分析介紹,需要的朋友參考下
在Java 5.0之前啟動(dòng)一個(gè)任務(wù)是通過調(diào)用Thread類的start()方法來實(shí)現(xiàn)的,任務(wù)的提于交和執(zhí)行是同時(shí)進(jìn)行的,如果你想對任務(wù)的執(zhí)行進(jìn)行調(diào)度或是控制 同時(shí)執(zhí)行的線程數(shù)量就需要額外編寫代碼來完成。5.0里提供了一個(gè)新的任務(wù)執(zhí)行架構(gòu)使你可以輕松地調(diào)度和控制任務(wù)的執(zhí)行,并且可以建立一個(gè)類似數(shù)據(jù)庫連接 池的線程池來執(zhí)行任務(wù)。這個(gè)架構(gòu)主要有三個(gè)接口和其相應(yīng)的具體類組成。這三個(gè)接口是Executor, ExecutorService、ScheduledExecutorService,讓我們先用一個(gè)圖來顯示它們的關(guān)系:

圖的左側(cè)是接口,圖的右側(cè)是這些接口的具體類。注意Executor是沒有直接具體實(shí)現(xiàn)的。
Executor接口:是用來執(zhí)行Runnable任務(wù)的,它只定義一個(gè)方法:
•execute(Runnable command):執(zhí)行Ruannable類型的任務(wù)
ExecutorService接口:ExecutorService繼承了Executor的方法,并提供了執(zhí)行Callable任務(wù)和中止任務(wù)執(zhí)行的服務(wù),其定義的方法主要有:
•submit(task):可用來提交Callable或Runnable任務(wù),并返回代表此任務(wù)的Future對象
•invokeAll(collection of tasks):批處理任務(wù)集合,并返回一個(gè)代表這些任務(wù)的Future對象集合
•shutdown():在完成已提交的任務(wù)后關(guān)閉服務(wù),不再接受新任務(wù)
•shutdownNow():停止所有正在執(zhí)行的任務(wù)并關(guān)閉服務(wù)。
•isTerminated():測試是否所有任務(wù)都執(zhí)行完畢了。
•isShutdown():測試是否該ExecutorService已被關(guān)閉
ScheduledExecutorService接口在ExecutorService的基礎(chǔ)上,ScheduledExecutorService提供了按時(shí)間安排執(zhí)行任務(wù)的功能,它提供的方法主要有:
•schedule(task, initDelay): 安排所提交的Callable或Runnable任務(wù)在initDelay指定的時(shí)間后執(zhí)行。
•scheduleAtFixedRate():安排所提交的Runnable任務(wù)按指定的間隔重復(fù)執(zhí)行
•scheduleWithFixedDelay():安排所提交的Runnable任務(wù)在每次執(zhí)行完后,等待delay所指定的時(shí)間后重復(fù)執(zhí)行。
重要的Executors類
雖然以上提到的接口有其實(shí)現(xiàn)的具體類,但為了方便Java 5.0建議使用Executors的工具類來得到Executor接口的具體對象,需要注意的是Executors是一個(gè)類,不是Executor的復(fù)數(shù) 形式。Executors提供了以下一些static的方法:
•callable(Runnable task):將Runnable的任務(wù)轉(zhuǎn)化成Callable的任務(wù)
•newSingleThreadExecutor:產(chǎn)生一個(gè)ExecutorService對象,這個(gè)對象只有一個(gè)線程可用來執(zhí)行任務(wù),若任務(wù)多于一個(gè),任務(wù)將按先后順序執(zhí)行。
•newCachedThreadPool():產(chǎn)生一個(gè)ExecutorService對象,這個(gè)對象帶有一個(gè)線程池,線程池的大小會根據(jù)需要調(diào)整,線程執(zhí)行完任務(wù)后返回線程池,供執(zhí)行下一次任務(wù)使用。
•newFixedThreadPool(int poolSize):產(chǎn)生一個(gè)ExecutorService對象,這個(gè)對象帶有一個(gè)大小為poolSize的線程池,若任務(wù)數(shù)量大于poolSize,任務(wù)會被放在一個(gè)queue里順序執(zhí)行。
•newSingleThreadScheduledExecutor:產(chǎn)生一個(gè)ScheduledExecutorService對象,這個(gè)對象的線程池大小為1,若任務(wù)多于一個(gè),任務(wù)將按先后順序執(zhí)行。
•newScheduledThreadPool(int poolSize):產(chǎn)生一個(gè)ScheduledExecutorService對象,這個(gè)對象的線程池大小為poolSize,若任務(wù)數(shù)量大于poolSize,任務(wù)會在一個(gè)queue里等待執(zhí)行
舉例說明:
應(yīng)用Executors來建立Thread pool
有時(shí)候您需要建立一堆Thread來執(zhí)行一些小任務(wù),然而頻繁的建立Thread有時(shí)會是個(gè)開銷,因?yàn)門hread的建立必須與作業(yè)系統(tǒng)互動(dòng),如果能建立一個(gè)Thread pool來管理這些小的Thread并加以重復(fù)使用,對于系統(tǒng)效能會是個(gè)改善的方式。
您可以使用Executors來建立Thread pool,Executors有幾個(gè)static方法,列出如下:
舉個(gè)簡單的實(shí)例,下面的程式使用newFixedThreadPool方法建立Thread pool,當(dāng)中包括五個(gè)可以重復(fù)使用的Thread,您可以指定Runnable物件給它,程式中會產(chǎn)生十個(gè)Runnable物件,由于Thread pool中只有五個(gè)可用的Thread,所以后來建立的五個(gè)Runnable必須等待有空閑的Thread才會被執(zhí)行:
•ExecutorDemo.java
package onlyfun.caterpillar;
import java.util.concurrent.ExecutorService;
import java.util.concurrent.Executors;
public class ExecutorDemo {
public static void main(String[] args) {
ExecutorService service = Executors.newFixedThreadPool(5);
for(int i = 0; i < 10; i++) {
final int count = i;
service.submit
(new Runnable() {
public void run() {
System.out.println(count);
try {
Thread.sleep(2000);
} catch (InterruptedException e) {
e.printStackTrace();
}
}
});
}
service.shutdown(); // 最后記得關(guān)閉Thread pool
}
}
submit()方法也接受實(shí)作Callable介面的物件,最后傳回Future物件,可以取得Callable執(zhí)行過后的傳回結(jié)果。如果想利用Executors進(jìn)行排程,例如排定某個(gè)工作30秒后執(zhí)行:
ScheduledExecutorService scheduler = Executors.newSingleThreadScheduledExecutor( );
scheduler.schedule(new Runnable( ) {
public void run() {
// 排程工作
}
},
30, TimeUnit.SECONDS);
或排定某個(gè)工作5秒后執(zhí)行,之后每30秒執(zhí)行一次:
final ScheduledFuture future = scheduler.scheduleAtFixedRate(new Runnable( ) {
public void run() {
// 排程工作
System.out.println("t");
}
},
0, 5, TimeUnit.SECONDS);
// 排定 60 秒后取消future
scheduler.schedule(new Runnable( ) {
public void run( ) {
future.cancel(false);
}
}, 60, TimeUnit.SECONDS);
如上所示,想要取消排程任務(wù),可以呼叫ScheduledFuture的cancel()方法。

圖的左側(cè)是接口,圖的右側(cè)是這些接口的具體類。注意Executor是沒有直接具體實(shí)現(xiàn)的。
Executor接口:是用來執(zhí)行Runnable任務(wù)的,它只定義一個(gè)方法:
•execute(Runnable command):執(zhí)行Ruannable類型的任務(wù)
ExecutorService接口:ExecutorService繼承了Executor的方法,并提供了執(zhí)行Callable任務(wù)和中止任務(wù)執(zhí)行的服務(wù),其定義的方法主要有:
•submit(task):可用來提交Callable或Runnable任務(wù),并返回代表此任務(wù)的Future對象
•invokeAll(collection of tasks):批處理任務(wù)集合,并返回一個(gè)代表這些任務(wù)的Future對象集合
•shutdown():在完成已提交的任務(wù)后關(guān)閉服務(wù),不再接受新任務(wù)
•shutdownNow():停止所有正在執(zhí)行的任務(wù)并關(guān)閉服務(wù)。
•isTerminated():測試是否所有任務(wù)都執(zhí)行完畢了。
•isShutdown():測試是否該ExecutorService已被關(guān)閉
ScheduledExecutorService接口在ExecutorService的基礎(chǔ)上,ScheduledExecutorService提供了按時(shí)間安排執(zhí)行任務(wù)的功能,它提供的方法主要有:
•schedule(task, initDelay): 安排所提交的Callable或Runnable任務(wù)在initDelay指定的時(shí)間后執(zhí)行。
•scheduleAtFixedRate():安排所提交的Runnable任務(wù)按指定的間隔重復(fù)執(zhí)行
•scheduleWithFixedDelay():安排所提交的Runnable任務(wù)在每次執(zhí)行完后,等待delay所指定的時(shí)間后重復(fù)執(zhí)行。
重要的Executors類
雖然以上提到的接口有其實(shí)現(xiàn)的具體類,但為了方便Java 5.0建議使用Executors的工具類來得到Executor接口的具體對象,需要注意的是Executors是一個(gè)類,不是Executor的復(fù)數(shù) 形式。Executors提供了以下一些static的方法:
•callable(Runnable task):將Runnable的任務(wù)轉(zhuǎn)化成Callable的任務(wù)
•newSingleThreadExecutor:產(chǎn)生一個(gè)ExecutorService對象,這個(gè)對象只有一個(gè)線程可用來執(zhí)行任務(wù),若任務(wù)多于一個(gè),任務(wù)將按先后順序執(zhí)行。
•newCachedThreadPool():產(chǎn)生一個(gè)ExecutorService對象,這個(gè)對象帶有一個(gè)線程池,線程池的大小會根據(jù)需要調(diào)整,線程執(zhí)行完任務(wù)后返回線程池,供執(zhí)行下一次任務(wù)使用。
•newFixedThreadPool(int poolSize):產(chǎn)生一個(gè)ExecutorService對象,這個(gè)對象帶有一個(gè)大小為poolSize的線程池,若任務(wù)數(shù)量大于poolSize,任務(wù)會被放在一個(gè)queue里順序執(zhí)行。
•newSingleThreadScheduledExecutor:產(chǎn)生一個(gè)ScheduledExecutorService對象,這個(gè)對象的線程池大小為1,若任務(wù)多于一個(gè),任務(wù)將按先后順序執(zhí)行。
•newScheduledThreadPool(int poolSize):產(chǎn)生一個(gè)ScheduledExecutorService對象,這個(gè)對象的線程池大小為poolSize,若任務(wù)數(shù)量大于poolSize,任務(wù)會在一個(gè)queue里等待執(zhí)行
舉例說明:
應(yīng)用Executors來建立Thread pool
有時(shí)候您需要建立一堆Thread來執(zhí)行一些小任務(wù),然而頻繁的建立Thread有時(shí)會是個(gè)開銷,因?yàn)門hread的建立必須與作業(yè)系統(tǒng)互動(dòng),如果能建立一個(gè)Thread pool來管理這些小的Thread并加以重復(fù)使用,對于系統(tǒng)效能會是個(gè)改善的方式。
您可以使用Executors來建立Thread pool,Executors有幾個(gè)static方法,列出如下:
方法 | 說明 |
newCachedThreadPool | 建立可以快取的Thread,每個(gè)Thread預(yù)設(shè)可idle 60秒 |
newFixedThreadPool |
包括固定數(shù)量的Thread |
newSingleThreadExecutor |
只有一個(gè)Thread,循序的執(zhí)行指定給它的每個(gè)任務(wù) |
newScheduledThreadPool | 可排程的Thread |
newSingleThreadScheduledExecutor | 單一可排程的Thread |
舉個(gè)簡單的實(shí)例,下面的程式使用newFixedThreadPool方法建立Thread pool,當(dāng)中包括五個(gè)可以重復(fù)使用的Thread,您可以指定Runnable物件給它,程式中會產(chǎn)生十個(gè)Runnable物件,由于Thread pool中只有五個(gè)可用的Thread,所以后來建立的五個(gè)Runnable必須等待有空閑的Thread才會被執(zhí)行:
•ExecutorDemo.java
復(fù)制代碼 代碼如下:
package onlyfun.caterpillar;
import java.util.concurrent.ExecutorService;
import java.util.concurrent.Executors;
public class ExecutorDemo {
public static void main(String[] args) {
ExecutorService service = Executors.newFixedThreadPool(5);
for(int i = 0; i < 10; i++) {
final int count = i;
service.submit
(new Runnable() {
public void run() {
System.out.println(count);
try {
Thread.sleep(2000);
} catch (InterruptedException e) {
e.printStackTrace();
}
}
});
}
service.shutdown(); // 最后記得關(guān)閉Thread pool
}
}
submit()方法也接受實(shí)作Callable介面的物件,最后傳回Future物件,可以取得Callable執(zhí)行過后的傳回結(jié)果。如果想利用Executors進(jìn)行排程,例如排定某個(gè)工作30秒后執(zhí)行:
復(fù)制代碼 代碼如下:
ScheduledExecutorService scheduler = Executors.newSingleThreadScheduledExecutor( );
scheduler.schedule(new Runnable( ) {
public void run() {
// 排程工作
}
},
30, TimeUnit.SECONDS);
或排定某個(gè)工作5秒后執(zhí)行,之后每30秒執(zhí)行一次:
復(fù)制代碼 代碼如下:
final ScheduledFuture future = scheduler.scheduleAtFixedRate(new Runnable( ) {
public void run() {
// 排程工作
System.out.println("t");
}
},
0, 5, TimeUnit.SECONDS);
// 排定 60 秒后取消future
scheduler.schedule(new Runnable( ) {
public void run( ) {
future.cancel(false);
}
}, 60, TimeUnit.SECONDS);
如上所示,想要取消排程任務(wù),可以呼叫ScheduledFuture的cancel()方法。
相關(guān)文章
C語言中獲取進(jìn)程識別碼的相關(guān)函數(shù)
這篇文章主要介紹了C語言中獲取進(jìn)程識別碼的相關(guān)函數(shù),分別為getpid()函數(shù)和getppid()函數(shù)的使用,需要的朋友可以參考下2015-08-08C語言鏈表實(shí)現(xiàn)歌手評分系統(tǒng)
這篇文章主要為大家詳細(xì)介紹了C語言鏈表實(shí)現(xiàn)歌手評分系統(tǒng),文中示例代碼介紹的非常詳細(xì),具有一定的參考價(jià)值,感興趣的小伙伴們可以參考一下2019-03-03C++ 內(nèi)存分配處理函數(shù)set_new_handler的使用
這篇文章主要介紹了C++ 內(nèi)存分配處理函數(shù)set_new_handler的使用,文中通過示例代碼介紹的非常詳細(xì),對大家的學(xué)習(xí)或者工作具有一定的參考學(xué)習(xí)價(jià)值,需要的朋友們下面隨著小編來一起學(xué)習(xí)學(xué)習(xí)吧2020-02-02Qt利用ImageWatch實(shí)現(xiàn)圖片查看功能
Visual Studio有專門針對OpenCV開發(fā)的插件,名叫ImageWatch,圖片放大之后可以查看RGB的像素值。本文將利用這一查件實(shí)現(xiàn)圖片查看功能,需要的可以參考一下2022-04-04Java C++算法題解leetcode1592重新排列單詞間的空格
這篇文章主要為大家介紹了Java C++算法題解leetcode1592重新排列單詞間的空格示例,有需要的朋友可以借鑒參考下,希望能夠有所幫助,祝大家多多進(jìn)步,早日升職加薪2022-09-09C++中?‘=default?’及‘?=delete?’的使用
這篇文章主要介紹了C++中?=default?及?=delete?使用,使用=default和=delete可以控制編譯器默認(rèn)函數(shù)體的使用,下面我們就來看看具體的室友方法吧,需要的朋友也可以參考一下2021-12-12