多線程知識(shí)點(diǎn)目錄
多線程并發(fā)(1)- http://www.reibang.com/p/8fcfcac74033
多線程并發(fā)(2)-http://www.reibang.com/p/a0c5095ad103
多線程并發(fā)(3)-http://www.reibang.com/p/c5c3bbd42c35
多線程并發(fā)(4)-http://www.reibang.com/p/e45807a9853e
多線程并發(fā)(5)-http://www.reibang.com/p/5217588d82ba
多線程并發(fā)(6)-http://www.reibang.com/p/d7c888a9c03c
七忽孽、Java后臺(tái)線程(守護(hù)線程)
定義:守護(hù)線程,也稱“服務(wù)線程”常挚,是一種特殊的線程,這種線程不屬于程序中不可或缺的一部分稽物,當(dāng)沒有用戶線程可服務(wù)時(shí)奄毡,后臺(tái)線程會(huì)自動(dòng)離開。
優(yōu)先級(jí):守護(hù)線程的優(yōu)先級(jí)比較低贝或,用來在后臺(tái)為系統(tǒng)中其他對(duì)象和線程提供服務(wù)吼过。
設(shè)置:通過setDaemon(true)來設(shè)置線程為“守護(hù)線程”。將一個(gè)用戶線程設(shè)置為守護(hù)線程的方式是在線程對(duì)象創(chuàng)建之前咪奖,調(diào)用線程對(duì)象的setDaemon()方法那先。
在Daemon線程中產(chǎn)生的新線程也是Daemon線程。
線程是JVM級(jí)別的赡艰,獨(dú)立于具體的Java應(yīng)用程序售淡,生命周期是由操作系統(tǒng)來管理。以Tomcat為例慷垮,它在Web應(yīng)用中啟動(dòng)的線程并不會(huì)與Web應(yīng)用保持同步的生命周期揖闸。即使你停止了Web應(yīng)用,這個(gè)線程仍然會(huì)繼續(xù)運(yùn)行料身。
守護(hù)線程示例:垃圾回收線程汤纸。當(dāng)程序中不再有任何運(yùn)行的Thread,程序就不會(huì)再產(chǎn)生垃圾芹血,垃圾回收器就無事可做贮泞,*所以當(dāng)垃圾回收線程是JVM上僅剩的線程時(shí),垃圾回收線程會(huì)自動(dòng)離開幔烛。它始終在低級(jí)別的狀態(tài)中運(yùn)行啃擦,用于實(shí)時(shí)監(jiān)控和管理系統(tǒng)中的可回收資源。
生命周期:守護(hù)進(jìn)程(Daemon)是運(yùn)行在后臺(tái)的一種特殊進(jìn)程饿悬,它不與用戶進(jìn)行交互令蛉,也不依賴于終端。守護(hù)線程不會(huì)受到用戶終端的控制狡恬,它會(huì)按照一定的周期或條件執(zhí)行特定的任務(wù)珠叔,或者等待處理某些事件。守護(hù)線程不依賴于用戶終端弟劲,但它依賴于操作系統(tǒng)祷安。當(dāng)系統(tǒng)運(yùn)行時(shí),守護(hù)線程會(huì)一直存在并執(zhí)行任務(wù)兔乞,當(dāng)系統(tǒng)關(guān)閉時(shí)汇鞭,守護(hù)線程也會(huì)終止撇眯。如果JVM中的所有線程都是守護(hù)線程,那么JVM會(huì)認(rèn)為沒有需要繼續(xù)運(yùn)行的線程虱咧,因此可以退出熊榛。但如果還有非守護(hù)線程在運(yùn)行,那么JVM會(huì)認(rèn)為還有其他工作需要完成腕巡,因此不會(huì)退出玄坦。(簡(jiǎn)單來說:守護(hù)線程是一種在后臺(tái)運(yùn)行并執(zhí)行特定任務(wù)的特殊線程。它是獨(dú)立于用戶終端的绘沉,但依賴于操作系統(tǒng)煎楣。當(dāng)系統(tǒng)中沒有非守護(hù)線程時(shí),JVM會(huì)選擇退出)
八车伞、JAVA鎖
8.1 樂觀鎖
樂觀鎖是一種樂觀思想择懂,即認(rèn)為讀多寫少,遇到并發(fā)寫的可能性低另玖,拿取數(shù)據(jù)時(shí)認(rèn)為別人不會(huì)修改困曙,所以不上鎖,但是在更新的時(shí)候會(huì)判斷一下在次期間別人有沒有去更新這個(gè)數(shù)據(jù)谦去,采取先讀出當(dāng)前版本號(hào)慷丽,然后加鎖操作,比較跟上一次的版本號(hào)鳄哭,一樣則更新要糊,如果失敗則重讀-比較-寫操作。
Java中的樂觀鎖基本都是通過CAS操作實(shí)現(xiàn)的妆丘,CAS是一種更新的原子操作锄俄,比較當(dāng)前值跟傳入值是否相同,同則更新勺拣,否則失敗奶赠。
8.2 悲觀鎖
悲觀鎖是一種悲觀思想,即認(rèn)為寫多宣脉,遇到并發(fā)寫的可能性高车柠,拿取數(shù)據(jù)時(shí)認(rèn)為別人會(huì)修改剔氏,所以每次在讀寫數(shù)據(jù)的時(shí)候都會(huì)上鎖塑猖,這樣別人想讀寫這個(gè)數(shù)據(jù)就會(huì)block直到拿到鎖。
Java中的悲觀鎖就是Synchronized谈跛,AQS框架下的鎖則是先嘗試CAS樂觀鎖去獲取鎖羊苟,獲取不到才會(huì)轉(zhuǎn)換為悲觀鎖,如RetreenLock感憾。
8.3 自旋鎖
自旋鎖原理:如果持有鎖的線程能再很短時(shí)間內(nèi)釋放鎖資源蜡励,那么那些等待競(jìng)爭(zhēng)鎖的線程就不需要做內(nèi)核態(tài)和用戶態(tài)之間的切換進(jìn)入阻塞掛起狀態(tài),它們只需要等一等(自旋),等待有鎖的線程釋放鎖后立即獲取凉倚,就避免用戶線程和內(nèi)核的切換的消耗兼都。
線程自旋是需要消耗CPU的,如果一直獲取不到鎖稽寒,那線程也不能一直占用CPU自旋做無用功扮碧,所以需要設(shè)定一個(gè)自旋等待的最大時(shí)間。
如果持有鎖的線程執(zhí)行的時(shí)間超過自旋等待的最大時(shí)間仍沒有釋放鎖杏糙,則會(huì)導(dǎo)致其它爭(zhēng)用鎖的線程在最大等待時(shí)間內(nèi)還是獲取不到鎖慎王,這時(shí)爭(zhēng)用線程會(huì)停止自旋,進(jìn)入阻塞狀態(tài)宏侍。
8.4 Synchronized同步鎖
synchronized可以把任意一個(gè)非NULL的對(duì)象當(dāng)作鎖赖淤。它屬于獨(dú)占式的悲觀鎖,同時(shí)屬于可重入鎖谅河。
synchronized作用范圍
- 作用于方法時(shí)咱旱,鎖住的是對(duì)象的實(shí)例(this)
- 作用于靜態(tài)方法時(shí),鎖住的是Class實(shí)例绷耍,又因?yàn)镃lass的相關(guān)數(shù)據(jù)存儲(chǔ)在永久帶PermGen(JDK1.8則是metaspace)莽龟,永久帶是全局共享的,因此靜態(tài)方法鎖相當(dāng)于類的一個(gè)全局鎖锨天,會(huì)鎖所有調(diào)用該方法的線程
- 作用于一個(gè)對(duì)象實(shí)例時(shí)毯盈,鎖住的是所有以該對(duì)象為鎖的代碼塊。它有過個(gè)隊(duì)列病袄,當(dāng)多個(gè)線程一起訪問某個(gè)對(duì)象監(jiān)視器時(shí)搂赋,對(duì)象監(jiān)視器會(huì)將這些線程存儲(chǔ)在不同的容器中。
synchronized核心組件
- Wait Set(等待集合):那些調(diào)用wait方法被阻塞的線程被放置在這里
- Contention List(鎖競(jìng)爭(zhēng)隊(duì)列):競(jìng)爭(zhēng)隊(duì)列益缠,所有請(qǐng)求鎖的線程首先被放在這個(gè)競(jìng)爭(zhēng)隊(duì)列中
- Entry List(競(jìng)爭(zhēng)候選列表):Contention List中那些有資格成為候選資源的線程被移動(dòng)到Entry List中
- OnDeck(待處理隊(duì)列):任意時(shí)刻脑奠,最多只有一個(gè)線程正在競(jìng)爭(zhēng)鎖資源,該線程被稱為OnDeck
- Owner(持鎖狀態(tài)):當(dāng)前已經(jīng)獲取到所有資源的線程稱為Owner
- !Owner:當(dāng)前釋放鎖的線程
synchronized實(shí)現(xiàn)機(jī)制
8.5 ReentrantLock
ReentrantLock繼承接口Lock并實(shí)現(xiàn)了接口中定義的方法幅慌,他是一種可重入鎖宋欺,除了能完成synchronized所能完成的所有工作外,還提供了諸如可響應(yīng)中斷鎖胰伍、可輪詢鎖請(qǐng)求齿诞、定時(shí)鎖等避免多線程死鎖的方法。
ReentrantLock特性
可重入:意味著一個(gè)線程可以多次獲取同一個(gè)鎖骂租,而不會(huì)產(chǎn)生死鎖祷杈。
公平鎖:ReentrantLock 可以配置為公平鎖和非公平鎖。公平鎖按照線程請(qǐng)求鎖的順序來分配鎖渗饮,而非公平鎖則沒有這個(gè)限制但汞。
可中斷:當(dāng)一個(gè)線程持有鎖時(shí)宿刮,其他線程可以嘗試獲取鎖,如果獲取失敗私蕾,那么這個(gè)線程可以選擇中斷等待的線程僵缺。
可嘗試:可以嘗試獲取鎖,而不會(huì)阻塞當(dāng)前線程踩叭。
ReentrantLock使用
import java.util.concurrent.locks.ReentrantLock;
public class ReentrantLockExample {
private final ReentrantLock lock = new ReentrantLock();
public void accessResource() {
// 獲取鎖
lock.lock(); // block until condition holds
try {
// ... method body
} finally {
// 釋放鎖
lock.unlock()
}
}
}
公平鎖 & 非公平鎖
公平鎖:通常先對(duì)鎖提出獲取請(qǐng)求的線程會(huì)先被分配到鎖谤饭。
非公平鎖:JVM按隨機(jī)、就近原則分配鎖的機(jī)制懊纳。
效率:非公平鎖執(zhí)行的效率要遠(yuǎn)遠(yuǎn)超出公平鎖揉抵,除非程序有特殊需求,否則最常用非公平鎖嗤疯。
可以通過在創(chuàng)建 ReentrantLock 時(shí)設(shè)置參數(shù)來選擇使用公平鎖還是非公平鎖冤今,默認(rèn)為非公平鎖。
// 公平鎖 - 鎖會(huì)盡可能地按照線程請(qǐng)求的順序分配
ReentrantLock fairLock = new ReentrantLock(true);
// 非公平鎖
ReentrantLock unfairLock = new ReentrantLock(false);
ReentrantLock 與 Synchronized
- ReentrantLock通過方法lock()與unlock()來進(jìn)行加鎖與解鎖操作茂缚,與Synchronized會(huì)被JVM自動(dòng)解鎖機(jī)制不同戏罢,ReentrantLock加鎖后需要手動(dòng)進(jìn)行解鎖。為了避免程序出現(xiàn)異常而無法正常解鎖的情況脚囊,使用ReentrantLock必須在finally控制塊中進(jìn)行解鎖操作龟糕。
- ReentrantLock相比Synchronized的優(yōu)勢(shì)是可中斷、公平鎖悔耘、多個(gè)鎖讲岁。這種情況下需要使用ReentrantLock。
8.6 Senaphore信號(hào)量
Semaphore是一種基于計(jì)數(shù)的信號(hào)量衬以。它可以設(shè)定一個(gè)閥值缓艳,基于此,多個(gè)線程競(jìng)爭(zhēng)獲取許可信號(hào)看峻,做完自己的申請(qǐng)后歸還阶淘,超過閥值后,線程申請(qǐng)?jiān)S可信號(hào)將會(huì)被阻塞互妓。Semaphore可用來構(gòu)建一些對(duì)象池溪窒、資源池之類的,比如數(shù)據(jù)庫(kù)連接池冯勉。
實(shí)現(xiàn)互斥鎖(計(jì)數(shù)器為1):創(chuàng)建計(jì)數(shù)為1的Semaphore澈蚌,將其作為一種類似互斥鎖的機(jī)制,這也叫二元信號(hào)量珠闰,表示兩種互斥狀態(tài)惜浅。
import java.util.concurrent.Semaphore;
public class SemaphoreExample {
private static Semaphore semaphore = new Semaphore(3); // 允許3個(gè)線程同時(shí)訪問共享資源
public static void main(String[] args) {
for (int i = 0; i < 5; i++) {
new Thread(() -> {
try {
semaphore.acquire(); // 獲取一個(gè)許可證,如果沒有伏嗜,線程將阻塞直到有一個(gè)可用
System.out.println("Thread " + Thread.currentThread().getId() + " is accessing the resource.");
Thread.sleep(1000); // 模擬資源訪問時(shí)間
System.out.println("Thread " + Thread.currentThread().getId() + " finished accessing the resource.");
semaphore.release(); // 釋放許可證坛悉,允許其他線程獲取許可證并訪問資源
} catch (InterruptedException e) {
e.printStackTrace();
}
}).start();
}
}
}
在這個(gè)例子中,我們創(chuàng)建了一個(gè)信號(hào)量 semaphore承绸,初始化了3個(gè)許可證裸影。然后我們創(chuàng)建了5個(gè)線程,每個(gè)線程都會(huì)嘗試獲取許可證來訪問共享資源军熏。如果當(dāng)前沒有可用的許可證轩猩,線程將會(huì)被阻塞直到有一個(gè)可用。當(dāng)線程訪問完共享資源后荡澎,它會(huì)釋放一個(gè)許可證均践,這樣其他線程就可以獲取許可證并訪問資源。
Semaphore 與 ReentrantLock
Semaphore 基本能完成 ReentrantLock 的所有工作摩幔,使用方法也類似彤委,通過acquire()與release()方法來獲得和釋放臨界資源。
經(jīng)實(shí)測(cè)或衡,Semaphore.acquire()方法默認(rèn)為可響應(yīng)中斷鎖焦影,與ReentrantLock.lockInterruptibly()作用效果一致,也就是說在等待臨界資源的過程中可以被Thread.interrupt()方法中斷封断。
此外斯辰,Semaphore也實(shí)現(xiàn)了可輪詢的鎖請(qǐng)求與定時(shí)鎖的功能,除了方法名TryAcquire與tryLock不同坡疼,其使用方法與ReentrantLock幾乎一致彬呻。Semaphore也提供了公平與非公平鎖的機(jī)制,也可在構(gòu)造函數(shù)中進(jìn)行設(shè)定柄瑰。
Semaphore 的鎖釋放操作也由手動(dòng)進(jìn)行废岂,因此與 ReentrantLock 一樣,為避免線程因拋出異常而無法正常釋放鎖的情況發(fā)生狱意,釋放鎖的操作也必須在 finally 代碼塊中完成湖苞。
8.7 AtomicInteger
AtomicInteger是一個(gè)提供原子操作的Integer的類,常見的還有AtomicBoolean详囤、AtomicLong财骨、AtomicReference等,他們的實(shí)現(xiàn)原理相同藏姐,區(qū)別在與運(yùn)算對(duì)象類型不同隆箩。還可以通過AtomicReference<T>將一個(gè)對(duì)象的所有操作轉(zhuǎn)化成原子操作。
在多線程程序中羔杨,諸如++i或i++等運(yùn)算不具有原子性捌臊,是不安全的線程操作之一。通常我們會(huì)使用Synchronized將操作變成一個(gè)原子操作兜材,但JVM為此類操作特意提供了一些同步類理澎,使得使用更方便逞力,且使程序運(yùn)行效率更高。
8.8 ReadWriteLock讀寫鎖
Java提供了讀寫鎖糠爬,在讀的地方使用讀鎖寇荧,在寫的地方使用寫鎖,靈活控制执隧。
如果沒有寫鎖的情況下揩抡,讀是無阻塞的,在一定程度上提高了程序的執(zhí)行效率镀琉。多個(gè)讀鎖不互斥峦嗤,讀鎖與寫鎖互斥,這是由JVM控制的屋摔,無需我們來控制烁设。
九、線程上下文切換
時(shí)間片輪轉(zhuǎn)(或稱為時(shí)間片調(diào)度)是一種策略凡壤,CPU 依次為每個(gè)任務(wù)提供一段時(shí)間的服務(wù)署尤,然后把當(dāng)前任務(wù)的狀態(tài)保存下來,在加載下一任務(wù)的狀態(tài)后亚侠,繼續(xù)服務(wù)下一任務(wù)曹体,任務(wù)的狀態(tài)保存及再加載, 這段過程就叫做上下文切換。時(shí)間片輪轉(zhuǎn)的方式使多個(gè)任務(wù)在同一顆 CPU 上執(zhí)行變成了可能硝烂。
1)進(jìn)程
是指一個(gè)程序運(yùn)行的實(shí)例(又稱任務(wù))箕别。在Linux系統(tǒng)中,線程就是能并行運(yùn)行并且與他們的父進(jìn)程(創(chuàng)建他們的進(jìn)程)共享同一地址空間(一段內(nèi)存區(qū)域)和其他資源的輕量級(jí)的進(jìn)程滞谢。
2)上下文
指某一時(shí)間點(diǎn)CPU寄存器和程序計(jì)數(shù)器的內(nèi)容串稀。
3)寄存器
CPU內(nèi)部的數(shù)量較少但速度很快的內(nèi)存(與之對(duì)應(yīng)的是CPU外部相對(duì)較慢的RAM主內(nèi)存)。寄存器通過對(duì)常用值的快速訪問來提高計(jì)算機(jī)程序運(yùn)行的速度狮杨。
4)程序計(jì)數(shù)器
一個(gè)專用的寄存器母截,用于表明指令序列中CPU正在執(zhí)行的位置,存的值為正在執(zhí)行的指令的位置或者下一個(gè)將要被執(zhí)行的指令的位置橄教,具體依賴于特定的系統(tǒng)清寇。
5)PCB-“切換幀”
上下文切換可以認(rèn)為是內(nèi)核在CPU上對(duì)進(jìn)程進(jìn)行切換,上下文切換過程中的信息是保存在進(jìn)程控制塊(PCB, Process Control Block)中的护蝶。PCB還經(jīng)常被稱作“切換幀”华烟。信息會(huì)一直保存到CPU的內(nèi)存中,知道他們被再次使用持灰。
6)上下文切換的活動(dòng)
- 掛起一個(gè)進(jìn)程盔夜,將這個(gè)進(jìn)程在CPU中的狀態(tài)(上下文)存儲(chǔ)于內(nèi)存中的某處。
- 在內(nèi)存中檢索下一個(gè)進(jìn)程的上下文并將其在CPU的寄存器中回復(fù)。
- 跳轉(zhuǎn)到程序計(jì)數(shù)器所指向的位置(即進(jìn)程被中斷時(shí)的代碼行)喂链,以恢復(fù)該進(jìn)程在程序中返十。
7)引起上下文切換的原因
- 當(dāng)前執(zhí)行任務(wù)的時(shí)間片用完之后,系統(tǒng)CPU正常調(diào)度下一個(gè)任務(wù)衩藤;
- 當(dāng)前執(zhí)行任務(wù)碰到IO阻塞吧慢,調(diào)度器將此任務(wù)掛起涛漂,繼續(xù)下一任務(wù)赏表;
- 多個(gè)任務(wù)搶占鎖資源,當(dāng)前任務(wù)沒有搶到鎖資源匈仗,被調(diào)度器掛起瓢剿,繼續(xù)下一任務(wù);
- 用戶代碼掛起當(dāng)前任務(wù)悠轩,讓出CPU時(shí)間间狂;
- 硬件終端。
十火架、線程池原理
線程池做的工作主要是控制運(yùn)行的線程的數(shù)量鉴象,處理過程中將任務(wù)放入隊(duì)列,然后在線程創(chuàng)建后啟動(dòng)這些任務(wù)何鸡,如果線程數(shù)量超過了最大數(shù)量超出數(shù)量的線程排隊(duì)等待纺弊,等其他線程執(zhí)行完畢,再?gòu)年?duì)列中取出任務(wù)來執(zhí)行骡男。它的主要特點(diǎn)是:線程復(fù)用淆游、控制最大并發(fā)數(shù)、管理線程隔盛。
10.1 線程復(fù)用
每一個(gè)Thread的類都有一個(gè)start()方法犹菱。當(dāng)調(diào)用start()啟動(dòng)線程時(shí)Java虛擬機(jī)會(huì)調(diào)用該類的run()方法。那么該類的run()方法中就是調(diào)用了Runnable對(duì)象的run()方法吮炕。我們可以繼承重寫Thread類腊脱,再其start()方法中添加不斷循環(huán)調(diào)用傳遞過來的Runnable對(duì)象。這就是線程池的實(shí)現(xiàn)原理龙亲。循環(huán)方法中不斷獲取Runnable是用Queue實(shí)現(xiàn)的陕凹,在獲取下一個(gè)Runnable之前可以是阻塞的。
10.2 線程池的組成
- 線程池管理器:用于創(chuàng)建并管理線程池
- 工作線程:線程池中的線程
- 任務(wù)接口:每個(gè)任務(wù)必須實(shí)現(xiàn)的接口俱笛,用于工作線程調(diào)度其運(yùn)行
- 任務(wù)隊(duì)列:用于存放待處理的任務(wù)捆姜,提供一種緩沖機(jī)制
Java中的線程池是通過Executor框架實(shí)現(xiàn)的,該框架中用到了Executor迎膜、Executors泥技、ExecutorService、ThreadPoolExecutor磕仅、Callable和Future珊豹、FutureTask這幾個(gè)類簸呈。
10.3 拒絕策略
線程池中的線程已經(jīng)用完了,無法繼續(xù)為新任務(wù)服務(wù)店茶,同時(shí)蜕便,等待隊(duì)列也已經(jīng)排滿了,再也塞不下新任務(wù)了贩幻。這時(shí)候轿腺,我們就需要拒絕策略機(jī)制合理的處理這個(gè)問題。
JDK內(nèi)置的拒絕策略:
- AbortPolicy:直接拋出異常丛楚,組織系統(tǒng)正常運(yùn)行族壳。
- CallerRunsPolicy:只要線程池未關(guān)閉,該策略直接在調(diào)用者線程中趣些,運(yùn)行當(dāng)前被丟棄的任務(wù)仿荆。顯然這樣做不會(huì)真的丟棄任務(wù),但是坏平,任務(wù)提交線程的性能極有可能會(huì)急劇下降拢操。
- DiscardOldestPolicy:丟棄最老的一個(gè)請(qǐng)求,也就是即將被執(zhí)行的一個(gè)任務(wù)舶替,并嘗試再次提交當(dāng)前任務(wù)令境。
- DiscardPolicy:丟棄無法處理的任務(wù),不予任何處理坎穿。如果運(yùn)行任務(wù)丟失展父,這是最好的一種方案。
以上內(nèi)置拒絕策略均實(shí)現(xiàn)了RejectedExecutionHandler接口玲昧,若以上策略仍無法滿足實(shí)際需要栖茉,可拓展RejectedExecutionHandler接口。
10.4 Java線程池工作過程
- 線程池剛創(chuàng)建時(shí)孵延,里面沒有線程吕漂。任務(wù)隊(duì)列是作為參數(shù)傳進(jìn)來的。不過尘应,就算隊(duì)列里面有任務(wù)惶凝,線程池也不會(huì)馬上執(zhí)行它們。
- 當(dāng)調(diào)用execute()方法添加一個(gè)任務(wù)時(shí)犬钢,線程池會(huì)做如下判斷:
- (1)如果正在運(yùn)行的線程數(shù)量小于corePoolSize苍鲜,那么馬上創(chuàng)建線程運(yùn)行這個(gè)任務(wù);
- (2)如果正在運(yùn)行的線程數(shù)大于或等于corePoolSize玷犹,那么將這個(gè)任務(wù)放入隊(duì)列混滔。
- (3)如果這時(shí)候隊(duì)列滿了,而且正在運(yùn)行的線程數(shù)量小于maximimPoolSize,那么還是要?jiǎng)?chuàng)建非核心線程立即運(yùn)行這個(gè)任務(wù)坯屿。
- (4)如果隊(duì)列滿了油湖,而且正在運(yùn)行的線程數(shù)量大于或等于maximumPoolSize,那么線程池會(huì)拋出異常RejectExecutionExeption领跛。
- 當(dāng)一個(gè)線程完成任務(wù)時(shí)乏德,它會(huì)從隊(duì)列中取下一個(gè)任務(wù)來執(zhí)行。
- 當(dāng)一個(gè)線程無事可做吠昭,超過一定時(shí)間(KeepAliveTime)時(shí)喊括,線程池會(huì)判斷,如果當(dāng)前運(yùn)行的線程大于CorePoolSize怎诫,那么這個(gè)線程就被停掉瘾晃。所以線程池的所有任務(wù)完成后贷痪,它最終會(huì)縮到CorePoolSize的大小幻妓。