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

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

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

添加線程判斷順序:corePoolSize——workQueue——maxPoolSize
比如線程池的核心線程是5個,最大線程池大小為10個,隊列為50個。
則線程池的請求最多會創(chuàng)建5個,然后任務(wù)將被添加到隊列中,直到達(dá)到50。隊列已滿時,將創(chuàng)建最新的線程maxPoolSize,最多達(dá)到10個,如果再來任務(wù)就直接拒絕。
keepAliveTime:如果線程池當(dāng)前的線程數(shù)多于corePoolSize,那么如果多余的線程空閑時間超過keepAliveTime,那么就會終止。
ThreadFactory:
默認(rèn)使用Executors.defaultThreadFactory()
創(chuàng)建出來的線程都在同一個線程組。
如果自己指定ThreadFactory,那么就可以改變線程名、線程組、優(yōu)先級、是否是守護(hù)線程等等。
常見的3中隊列類型:
直接交接:SynchronousQueue
無界隊列:LinkedBlockingQueue
有界隊列:ArrayBlockingQueue
線程池應(yīng)該手動創(chuàng)建和自動創(chuàng)建那個更好?
手動創(chuàng)建好,因為這樣可以明確線程池的運(yùn)行規(guī)則和避開資源浪費的風(fēng)險。
- newFixedThreadPool:容易造成大量內(nèi)存占用,可能導(dǎo)致DOM
- newSingleThreadExecutor:當(dāng)請求堆積的時候,可能會占用大量內(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:弊端在于第二個參數(shù)maximumPoolSize被設(shè)置為了Integer.MAX_VALUE,這可能會創(chuàng)建數(shù)量非常多的線程,甚至導(dǎo)致DOM
- newScheduledThreadPool:原因和newCachedThreadPool一樣
//演示FixedThreadPool出錯
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();
}
}
}
常見的線程池:
FixedThreadPool

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

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

阻塞隊列分析:

5.停止線程池的方法
shutdown:只是將線程池的狀態(tài)設(shè)置為 shutdown 狀態(tài),但任務(wù)并沒有中斷,還是會繼續(xù)執(zhí)行下去。此時線程池不會接受新的任務(wù),只是將原有的任務(wù)執(zhí)行結(jié)束。shutdownNow:將線程池的狀態(tài)設(shè)置為STOP,正在執(zhí)行的任務(wù)會停止,沒被執(zhí)行的任務(wù)會被返回。isShutdown:當(dāng)調(diào)用shutdown()或shutdownNow()方法后返回為true,否則返回為false。isTerminated:線程任務(wù)全部執(zhí)行完返回trueawaitTerminated:有兩個參數(shù),第一個是long類型的數(shù)值,第二個是時間類型TimeUnit,用于設(shè)置阻塞時間。它是一個阻塞的方法,若線程池一直運(yùn)行則會一直阻塞,直到線程池關(guān)閉返回true,或阻塞時間超過你設(shè)置的這個時間,則返回false。此方法必須放在shutdown()方法之后,否則一直在阻塞,或超過設(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();
代碼實現(xiàn):
//演示每個任務(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ù)了");
}
}
實現(xiàn)原理及源碼分析:
線程池的組成部分:
- 線程池管理器
- 工作線程
- 任務(wù)隊列
- 任務(wù)接口(Task)

到此這篇關(guān)于Java線程池由淺入深掌握到精通的文章就介紹到這了,更多相關(guān)Java 線程池內(nèi)容請搜索腳本之家以前的文章或繼續(xù)瀏覽下面的相關(guān)文章希望大家以后多多支持腳本之家!
相關(guān)文章
IDEA 中創(chuàng)建Spring Data Jpa 項目的示例代碼
這篇文章主要介紹了IDEA 中創(chuàng)建Spring Data Jpa 項目的示例代碼,本文通過實例代碼給大家介紹的非常詳細(xì),對大家的學(xué)習(xí)或工作具有一定的參考借鑒價值,需要的朋友可以參考下2020-04-04
后端報TypeError:Cannot?read?properties?of?null?(reading?‘
這篇文章主要給大家介紹了關(guān)于后端報TypeError:Cannot?read?properties?of?null?(reading?‘xxx‘)錯誤的解決辦法,這個錯誤是開發(fā)中常見的錯誤之一,需要的朋友可以參考下2023-05-05
Spring?Boot?@Autowired?@Resource屬性賦值時機(jī)探究
這篇文章主要為大家介紹了Spring?Boot?@Autowired?@Resource屬性賦值時機(jī),有需要的朋友可以借鑒參考下,希望能夠有所幫助,祝大家多多進(jìn)步,早日升職加薪2023-07-07
Java?guava框架LoadingCache及CacheBuilder本地小容量緩存框架總結(jié)
Guava?Cache本地緩存框架主要是一種將本地數(shù)據(jù)緩存到內(nèi)存中,但數(shù)據(jù)量并不能太大,否則將會占用過多的內(nèi)存,本文給大家介紹Java?guava框架?LoadingCache及CacheBuilder?本地小容量緩存框架總結(jié),感興趣的朋友一起看看吧2023-12-12

