Java線程池由淺入深掌握到精通
1.為什么使用線程池?
反復(fù)創(chuàng)建線程開(kāi)銷大,可以復(fù)用線程池
過(guò)多的線程會(huì)占用太多的內(nèi)存
解決以上問(wèn)題的方法:
- 用少量的線程,避免內(nèi)存占用過(guò)多
- 讓這部分線程都保持工作,且反復(fù)執(zhí)行任務(wù),避免生命周期的損耗
2.線程池的好處:
加快響應(yīng)速度,提高用戶體驗(yàn)
合理利用CPU內(nèi)存
統(tǒng)一管理
3.線程池使用的場(chǎng)合
服務(wù)器接受大量請(qǐng)求時(shí),使用線程池技術(shù)是非常合適的,它可以大大減少線程的創(chuàng)建和銷毀次數(shù),提高服務(wù)器的工作效率。在實(shí)際開(kāi)發(fā)中,如果創(chuàng)建5個(gè)以上 的線程,那么就可以使用線程池來(lái)管理線程。
4.創(chuàng)建和停止線程
線程池構(gòu)造方法的參數(shù)?
線程池應(yīng)該手動(dòng)創(chuàng)建和自動(dòng)創(chuàng)建那個(gè)更好?
線程池里的線程數(shù)量設(shè)置未多少合適?
停止線程的正確方法?
線程池構(gòu)造函數(shù)的參數(shù):

corePoolSize: 核心線程數(shù)
線程池在完成初始化后,默認(rèn)情況下,線程池中并沒(méi)有任何線程,會(huì)等到有任務(wù)到來(lái)時(shí)再去創(chuàng)建新的線程去執(zhí)行任務(wù)。
maxPoolSize:在核心線程的基礎(chǔ)上,額外增加的線程數(shù)的上限。

根據(jù)圖可知添加線程的規(guī)則:
1.如果線程數(shù)小于corePoolSize,即使其他工作線程處于空閑狀態(tài),也會(huì)創(chuàng)建一個(gè)新線程來(lái)運(yùn)行任務(wù)。
2.如果線程數(shù)等于或大于corePoolSize但少于maximumPoolSize,則將任務(wù)放入隊(duì)列。
3.如果線程池已滿,并且線程數(shù)小于maxPoolSize,則創(chuàng)建一個(gè)新線程來(lái)運(yùn)行任務(wù)。
4.如果隊(duì)列已滿,并且線程數(shù)大于或等于maxPoolSzie,則參數(shù)拒絕該任務(wù)。

添加線程判斷順序:corePoolSize——workQueue——maxPoolSize
比如線程池的核心線程是5個(gè),最大線程池大小為10個(gè),隊(duì)列為50個(gè)。
則線程池的請(qǐng)求最多會(huì)創(chuàng)建5個(gè),然后任務(wù)將被添加到隊(duì)列中,直到達(dá)到50。隊(duì)列已滿時(shí),將創(chuàng)建最新的線程maxPoolSize,最多達(dá)到10個(gè),如果再來(lái)任務(wù)就直接拒絕。
keepAliveTime:如果線程池當(dāng)前的線程數(shù)多于corePoolSize,那么如果多余的線程空閑時(shí)間超過(guò)keepAliveTime,那么就會(huì)終止。
ThreadFactory:
默認(rèn)使用Executors.defaultThreadFactory()
創(chuàng)建出來(lái)的線程都在同一個(gè)線程組。
如果自己指定ThreadFactory,那么就可以改變線程名、線程組、優(yōu)先級(jí)、是否是守護(hù)線程等等。
常見(jiàn)的3中隊(duì)列類型:
直接交接:SynchronousQueue
無(wú)界隊(duì)列:LinkedBlockingQueue
有界隊(duì)列:ArrayBlockingQueue
線程池應(yīng)該手動(dòng)創(chuàng)建和自動(dòng)創(chuàng)建那個(gè)更好?
手動(dòng)創(chuàng)建好,因?yàn)檫@樣可以明確線程池的運(yùn)行規(guī)則和避開(kāi)資源浪費(fèi)的風(fēng)險(xiǎn)。
- newFixedThreadPool:容易造成大量?jī)?nèi)存占用,可能導(dǎo)致DOM
- newSingleThreadExecutor:當(dāng)請(qǐng)求堆積的時(shí)候,可能會(huì)占用大量?jī)?nèi)存。
public class FixedThreadPoolTest {
public static void main(String[] args) {
ExecutorService executorService = Executors.newFixedThreadPool(4);
for (int i = 0; i < 500; i++) {
executorService.execute(new Task());
}
}
}
class Task implements Runnable{
@Override
public void run() {
try {
Thread.sleep(500);
} catch (InterruptedException e) {
e.printStackTrace();
}
System.out.println(Thread.currentThread().getName());
}
}
- newCachedThreadPool:弊端在于第二個(gè)參數(shù)maximumPoolSize被設(shè)置為了Integer.MAX_VALUE,這可能會(huì)創(chuàng)建數(shù)量非常多的線程,甚至導(dǎo)致DOM
- newScheduledThreadPool:原因和newCachedThreadPool一樣
//演示FixedThreadPool出錯(cuò)
public class FixedThreadPoolOOM {
private static ExecutorService executorService = Executors.newFixedThreadPool(1);
public static void main(String[] args) {
for (int i = 0; i < Integer.MAX_VALUE; i++) {
executorService.execute(new SubThread());
}
}
}
class SubThread implements Runnable{
@Override
public void run() {
try {
Thread.sleep(10000000);
} catch (InterruptedException e) {
e.printStackTrace();
}
}
}
常見(jiàn)的線程池:
FixedThreadPool

CachedThreadPool:可緩存線程池,具有自動(dòng)回收多余線程的功能

ScheduledThreadPool:支持定時(shí)及周期性任務(wù)執(zhí)行的線程池
SingleThreadExecutor:?jiǎn)尉€程的線程池只會(huì)用唯一的工作線程來(lái)執(zhí)行任務(wù)
原理和FixedThreadPool一樣,但是線程數(shù)量被設(shè)為1
四種線程池的構(gòu)造方法的參數(shù):

阻塞隊(duì)列分析:

5.停止線程池的方法
shutdown:只是將線程池的狀態(tài)設(shè)置為 shutdown 狀態(tài),但任務(wù)并沒(méi)有中斷,還是會(huì)繼續(xù)執(zhí)行下去。此時(shí)線程池不會(huì)接受新的任務(wù),只是將原有的任務(wù)執(zhí)行結(jié)束。shutdownNow:將線程池的狀態(tài)設(shè)置為STOP,正在執(zhí)行的任務(wù)會(huì)停止,沒(méi)被執(zhí)行的任務(wù)會(huì)被返回。isShutdown:當(dāng)調(diào)用shutdown()或shutdownNow()方法后返回為true,否則返回為false。isTerminated:線程任務(wù)全部執(zhí)行完返回trueawaitTerminated:有兩個(gè)參數(shù),第一個(gè)是long類型的數(shù)值,第二個(gè)是時(shí)間類型TimeUnit,用于設(shè)置阻塞時(shí)間。它是一個(gè)阻塞的方法,若線程池一直運(yùn)行則會(huì)一直阻塞,直到線程池關(guān)閉返回true,或阻塞時(shí)間超過(guò)你設(shè)置的這個(gè)時(shí)間,則返回false。此方法必須放在shutdown()方法之后,否則一直在阻塞,或超過(guò)設(shè)置的阻塞時(shí)間返回false。
//演示關(guān)閉線程池
public class ShutDown {
public static void main(String[] args) throws InterruptedException {
ExecutorService executorService = Executors.newFixedThreadPool(10);
for (int i = 0; i < 500; i++) {
executorService.execute(new ShutDownTask());
}
Thread.sleep(1500);
// executorService.shutdown();
// System.out.println(executorService.isShutdown());
executorService.awaitTermination(3L, TimeUnit.SECONDS);
}
}
class ShutDownTask implements Runnable{
@Override
public void run() {
try {
Thread.sleep(500);
System.out.println(Thread.currentThread().getName());
} catch (InterruptedException e) {
e.printStackTrace();
}
}
}
6.暫停和恢復(fù)線程池
//暫停線程池 pauseAbleThreadPool.pause(); //恢復(fù)線程池 pauseAbleThreadPool.resume();
代碼實(shí)現(xiàn):
//演示每個(gè)任務(wù)執(zhí)行前后放鉤子函數(shù)
public class PauseAbleThreadPool extends ThreadPoolExecutor {
private final ReentrantLock lock = new ReentrantLock();
private Condition unpaused = lock.newCondition();
private boolean isPaused;
public PauseAbleThreadPool(int corePoolSize, int maximumPoolSize, long keepAliveTime, TimeUnit unit, BlockingQueue<Runnable> workQueue) {
super(corePoolSize, maximumPoolSize, keepAliveTime, unit, workQueue);
}
public PauseAbleThreadPool(int corePoolSize, int maximumPoolSize, long keepAliveTime, TimeUnit unit, BlockingQueue<Runnable> workQueue, ThreadFactory threadFactory) {
super(corePoolSize, maximumPoolSize, keepAliveTime, unit, workQueue, threadFactory);
}
public PauseAbleThreadPool(int corePoolSize, int maximumPoolSize, long keepAliveTime, TimeUnit unit, BlockingQueue<Runnable> workQueue, RejectedExecutionHandler handler) {
super(corePoolSize, maximumPoolSize, keepAliveTime, unit, workQueue, handler);
}
public PauseAbleThreadPool(int corePoolSize, int maximumPoolSize, long keepAliveTime, TimeUnit unit, BlockingQueue<Runnable> workQueue, ThreadFactory threadFactory, RejectedExecutionHandler handler) {
super(corePoolSize, maximumPoolSize, keepAliveTime, unit, workQueue, threadFactory, handler);
}
@Override
protected void beforeExecute(Thread t, Runnable r) {
super.beforeExecute(t, r);
lock.lock();
try {
while (isPaused) {
unpaused.await();
}
} catch (InterruptedException e) {
e.printStackTrace();
} finally {
lock.unlock();
}
}
private void pause() {
lock.lock();
try {
isPaused = true;
} finally {
lock.unlock();
}
}
public void resume() {
lock.lock();
try {
isPaused = false;
unpaused.signalAll();
} finally {
lock.unlock();
}
}
public static void main(String[] args) throws InterruptedException {
PauseAbleThreadPool pauseAbleThreadPool = new PauseAbleThreadPool(10, 20, 10l, TimeUnit.SECONDS, new LinkedBlockingQueue<>());
Runnable runnable = new Runnable() {
@Override
public void run() {
System.out.println("我被執(zhí)行");
try {
Thread.sleep(10);
} catch (InterruptedException e) {
e.printStackTrace();
}
}
};
for (int i = 0; i < 10000; i++) {
pauseAbleThreadPool.execute(runnable);
}
Thread.sleep(1500);
pauseAbleThreadPool.pause();
System.out.println("線程池被暫停了");
Thread.sleep(1500);
pauseAbleThreadPool.resume();
System.out.println("線程池被恢復(fù)了");
}
}
實(shí)現(xiàn)原理及源碼分析:
線程池的組成部分:
- 線程池管理器
- 工作線程
- 任務(wù)隊(duì)列
- 任務(wù)接口(Task)

到此這篇關(guān)于Java線程池由淺入深掌握到精通的文章就介紹到這了,更多相關(guān)Java 線程池內(nèi)容請(qǐng)搜索腳本之家以前的文章或繼續(xù)瀏覽下面的相關(guān)文章希望大家以后多多支持腳本之家!
相關(guān)文章
Java?對(duì)象在?JVM?中的內(nèi)存布局超詳細(xì)解說(shuō)
這篇文章主要介紹了Java?對(duì)象在?JVM?中的內(nèi)存布局超詳細(xì)解說(shuō),文章圍繞主題展開(kāi)詳細(xì)的內(nèi)容介紹,具有一定的參考價(jià)值,需要的小伙伴可以參考一下2022-09-09
Java應(yīng)用服務(wù)器之tomcat部署的詳細(xì)教程
這篇文章主要介紹了Java應(yīng)用服務(wù)器之tomcat部署,本文通過(guò)實(shí)例圖文相結(jié)合給大家介紹的非常詳細(xì),對(duì)大家的學(xué)習(xí)或工作具有一定的參考借鑒價(jià)值,需要的朋友可以參考下2020-07-07
SpringCloud學(xué)習(xí)筆記之SpringCloud搭建父工程的過(guò)程圖解
SpringCloud是分布式微服務(wù)架構(gòu)的一站式解決方案,十多種微服務(wù)架構(gòu)落地技術(shù)的集合體,俗稱微服務(wù)全家桶,這篇文章主要介紹了SpringCloud學(xué)習(xí)筆記(一)搭建父工程,需要的朋友可以參考下2021-10-10
JavaWeb實(shí)現(xiàn)mysql數(shù)據(jù)庫(kù)數(shù)據(jù)的添加和刪除
這篇文章主要介紹了如何利用JavaWeb實(shí)現(xiàn)mysql數(shù)據(jù)庫(kù)數(shù)據(jù)的添加和刪除功能,文中的示例代碼講解詳細(xì),感興趣的小伙伴可以了解一下2022-03-03
Java 模擬數(shù)據(jù)庫(kù)連接池的實(shí)現(xiàn)代碼
這篇文章主要介紹了Java 模擬數(shù)據(jù)庫(kù)連接池的實(shí)現(xiàn),本文通過(guò)實(shí)例代碼給大家介紹的非常詳細(xì),對(duì)大家的學(xué)習(xí)或工作具有一定的參考借鑒價(jià)值,需要的朋友可以參考下2021-02-02

