引言
最近在看項目中的代碼的時候,多次看到線程池的身影,於是小編就簡單總結了一些關於線程池的知識。
什麼是線程池?爲什麼要使用它?
線程池主要用來解決線程生命週期開銷問題和資源不足問題。通過對多個任務重複使用線程,線程創建的開銷就被分攤到了多個任務上了,而且由於在請求到達時線程已經存在,所以消除了線程創建所帶來的延遲。這樣,就可以立即爲請求服務,使用應用程序響應更快。另外,通過適當的調整線程中的線程數目可以防止出現資源不足的情況。
線程池的簡要工作模型
線程池的工作模型主要兩部分組成,一部分是運行Runnable的Thread對象,另一部分就是阻塞隊列。由線程池創建的Thread對象其內部的run方法會通過阻塞隊列的take方法獲取一個Runnable對象,然後執行這個Runnable對象的run方法(即,在Thread的run方法中調用Runnable對象的run方法)。當Runnable對象的run方法執行完畢以後,Thread中的run方法又循環的從阻塞隊列中獲取下一個Runnable對象繼續執行。這樣就實現了Thread對象的重複利用,也就減少了創建線程和銷燬線程所消耗的資源。當需要向線程池提交任務時會調用阻塞隊列的offer方法向隊列的尾部添加任務。提交的任務實際上就是是Runnable對象或Callable對象。
創建線程池的核心類繼承關係?
創建線程池需要配置的幾個參數?
corePoolSize
核心線程數,核心線程會一直存活,即使沒有任務需要處理。當線程數小於核心線程數時,即使現有的線程空閒,線程池也會優先創建新線程來處理任務,而不是直接交給現有的線程處理。
核心線程在allowCoreThreadTimeout被設置爲true時會超時退出,默認情況下不會退出。
maxPoolSize
當線程數大於或等於核心線程,且任務隊列已滿時,線程池會創建新的線程,直到線程數量達到maxPoolSize。如果線程數已等於maxPoolSize,且任務隊列已滿,則已超出線程池的處理能力,線程池會拒絕處理任務而拋出異常。
keepAliveTime
當線程空閒時間達到keepAliveTime,該線程會退出,直到線程數量等於corePoolSize。如果allowCoreThreadTimeout設置爲true,則所有線程均會退出直到線程數量爲0。
allowCoreThreadTimeout
是否允許核心線程空閒退出,默認值爲false。
queueCapacity
任務隊列容量。從maxPoolSize的描述上可以看出,任務隊列的容量會影響到線程的變化,因此任務隊列的長度也需要恰當的設置。
線程池的主要處理流程?
線程池的種類
newFixedThreadPool創建一個指定工作線程數量的線程池。每當提交一個任務就創建一個工作線程,如果工作線程數量達到線程池初始的最大數,則將提交的任務存入到池隊列中。
package test;
import java.util.concurrent.ExecutorService;
import java.util.concurrent.Executors;
public class ThreadPoolExecutorTest {
public static void main(String[] args) {
ExecutorService fixedThreadPool = Executors.newFixedThreadPool(3);
for (int i = 0; i < 10; i++) {
final int index = i;
fixedThreadPool.execute(new Runnable() {
public void run() {
try {
System.out.println(index);
Thread.sleep(2000);
} catch (InterruptedException e) {
e.printStackTrace();
}
}
});
}
}
}
newCachedThreadPool創建一個可緩存的線程池。這種類型的線程池特點是: 1).工作線程的創建數量幾乎沒有限制(其實也有限制的,數目爲Interger. MAX_VALUE), 這樣可靈活的往線程池中添加線程。
2).如果長時間沒有往線程池中提交任務,即如果工作線程空閒了指定的時間(默認爲1分鐘),則該工作線程將自動終止。終止後,如果你又提交了新的任務,則線程池重新創建一個工作線程。
package test;
import java.util.concurrent.ExecutorService;
import java.util.concurrent.Executors;
public class ThreadPoolExecutorTest {
public static void main(String[] args) {
ExecutorService cachedThreadPool = Executors.newCachedThreadPool();
for (int i = 0; i < 10; i++) {
final int index = i;
try {
Thread.sleep(index * 1000);
} catch (InterruptedException e) {
e.printStackTrace();
}
cachedThreadPool.execute(new Runnable() {
public void run() {
System.out.println(index);
}
});
}
}
}
newScheduleThreadPool創建一個定長的線程池,而且支持定時的以及週期性的任務執行,類似於Timer。
package test;
import java.util.concurrent.Executors;
import java.util.concurrent.ScheduledExecutorService;
import java.util.concurrent.TimeUnit;
public class ThreadPoolExecutorTest {
public static void main(String[] args) {
ScheduledExecutorService scheduledThreadPool = Executors.newScheduledThreadPool(5);
scheduledThreadPool.schedule(new Runnable() {
public void run() {
System.out.println("delay 3 seconds");
}
}, 3, TimeUnit.SECONDS);
}
}
newSingleThreadExecutor創建一個單線程化的Executor,即只創建唯一的工作者線程來執行任務,如果這個線程異常結束,會有另一個取代它,保證順序執行(我覺得這點是它的特色)。單工作線程最大的特點是可保證順序地執行各個任務,並且在任意給定的時間不會有多個線程是活動的 。
package test;
import java.util.concurrent.ExecutorService;
import java.util.concurrent.Executors;
public class ThreadPoolExecutorTest {
public static void main(String[] args) {
ExecutorService singleThreadExecutor = Executors.newSingleThreadExecutor();
for (int i = 0; i < 10; i++) {
final int index = i;
singleThreadExecutor.execute(new Runnable() {
public void run() {
try {
System.out.println(index);
Thread.sleep(2000);
} catch (InterruptedException e) {
e.printStackTrace();
}
}
});
}
}
}
總結:
一.FixedThreadPool是一個典型且優秀的線程池,它具有線程池提高程序效率和節省創建線程時所耗的開銷的優點。但是,在線程池空閒時,即線程池中沒有可運行任務時,它不會釋放工作線程,還會佔用一定的系統資源。
二.CachedThreadPool的特點就是在線程池空閒時,即線程池中沒有可運行任務時,它會釋放工作線程,從而釋放工作線程所佔用的資源。但是,但當出現新任務時,又要創建一新的工作線程,又要一定的系統開銷。並且,在使用CachedThreadPool時,一定要注意控制任務的數量,否則,由於大量線程同時運行,很有會造成系統癱瘓。小結
在我們項目中正確使用合適的線程池可以很大程度上提高我們系統的性能,在我們選擇線程池的種類的時候,需要我們瞭解這些線程池的工作原理和一些優劣,小編在本篇博客中總結了一些核心的東西,希望對您有幫助!