JavaEE線程安全實(shí)現(xiàn)線程池方法
前言:
線程雖然比進(jìn)程更輕量,但是如果創(chuàng)建銷毀的頻率進(jìn)一步增加,開銷還是很大
解決方案:線程池or協(xié)程
線程池:把線程提前創(chuàng)建好放到池子里,后續(xù)用到線程直接從池子里取不必這邊申請(qǐng)了。線程用完了也不是還給系統(tǒng)而是放回池子,以備下次再用。
為什么線程放在池子里就比從系統(tǒng)申請(qǐng)釋放來(lái)得更快呢?

用戶寫的代碼就是在最上面的應(yīng)用程序來(lái)運(yùn)行,這里的代碼都稱為“用戶態(tài)”運(yùn)行的代碼,有些代碼需要調(diào)用API進(jìn)一步的邏輯就會(huì)在內(nèi)核中執(zhí)行。在內(nèi)核中執(zhí)行的代碼稱為“內(nèi)核態(tài)”運(yùn)行的代碼。創(chuàng)建線程是在內(nèi)核中創(chuàng)建PCB加到鏈表里,本身就需要內(nèi)核的支持,調(diào)用Thread.start也是要在內(nèi)核態(tài)上運(yùn)行的。而創(chuàng)建好的線程放進(jìn)池子里是用戶態(tài)實(shí)現(xiàn)的,這個(gè)放進(jìn)池里/從池子里取過(guò)程不涉及內(nèi)核態(tài),就是用戶代碼就能完成。一般認(rèn)為純用戶態(tài)的操作效率要比內(nèi)核態(tài)處理的操作效率更高。
java標(biāo)準(zhǔn)庫(kù)中的線程池:
ThreadPoolExecutor需要java.util.concurrent包,Java中很多線程相關(guān)的組件都在concurrent包里
線程池構(gòu)造方法:
ThreadPoolExecutor(int corePoolSize, int maximumPoolSize, long keepAliveTime, TimeUnit unit, BlockingQueue<Runnable> workQueue, ThreadFactory threadFactory, RejectedExecutionHandler handler)
線程池參數(shù)解析:
int corePoolSize 核心線程數(shù)(正式員工的數(shù)量)
int maximumPoolSize 最大線程數(shù)(正式員工+臨時(shí)員工)
long keepAliveTime 允許臨時(shí)工摸魚的時(shí)間
TimeUnit unit 時(shí)間的單位(s,ms,us…)
BlockingQueue<Runnable workQueue 任務(wù)隊(duì)列(線程池會(huì)提供一個(gè)submit方法讓程序員把任務(wù)注冊(cè)到線程池中,加到這個(gè)任務(wù)隊(duì)列中)
ThreadFactory threadFactory 線程工廠(線程是怎么創(chuàng)建出來(lái)的)
RejectedExecutionHandler handler 拒絕策略
(當(dāng)任務(wù)滿了怎么做?1.直接忽略最新的任務(wù) 2.阻塞等待 3.直接丟棄最老的任務(wù) …)
一個(gè)程序要并發(fā)的/多線程的來(lái)完成一些任務(wù),如果使用線程池的話這里線程數(shù)量多少合適?
通過(guò)測(cè)試性能找到合適的值,例如,寫一個(gè)服務(wù)器程序通過(guò)線程池,多線程處理用戶請(qǐng)求就可以對(duì)這個(gè)服務(wù)器性能經(jīng)行測(cè)試。比如每秒發(fā)送500/1000/2000的請(qǐng)求…
根據(jù)不同線程池的線程數(shù)來(lái)觀察程序處理任務(wù)的速度和程序持有的CPU的占用率。當(dāng)線程數(shù)量多了整體速度是會(huì)變快但是CPU占用率也會(huì)高,當(dāng)線程數(shù)少了整體速度會(huì)變慢但是Cpu占用率也會(huì)下降。
需要找到一個(gè)讓程序速度能接受并且CPU占用也合理的平衡點(diǎn),不同類型的程序單個(gè)任務(wù)在CPU上計(jì)算時(shí)間和阻塞時(shí)間的分布是不相同的,因此不是一個(gè)確定的數(shù)字。
簡(jiǎn)化版的線程池:
Executors本質(zhì)是針對(duì)ThreadPoolExecutor進(jìn)行了封裝提供了一些默認(rèn)參數(shù)。
public class 線程池 {
public static void main(String[] args) {
// 創(chuàng)建一個(gè)固定線程數(shù)目的線程池. 參數(shù)指定了線程個(gè)數(shù)
ExecutorService pool = Executors.newFixedThreadPool(10);
//創(chuàng)建一個(gè)自動(dòng)擴(kuò)容的線程池,會(huì)根據(jù)任務(wù)量來(lái)進(jìn)行自動(dòng)擴(kuò)容
Executors.newCachedThreadPool();
//創(chuàng)建一個(gè)只有一個(gè)線程的線程池
Executors.newSingleThreadExecutor();
//創(chuàng)建一個(gè)帶有定時(shí)器功能的線程池,類似于Timer
Executors.newScheduledThreadPool(10);
for (int i = 0; i < 100; i++) {
pool.submit(new Runnable() {
@Override
public void run() {
System.out.println("hello threadpool");
}
});
}
}
}線程池的組成:
- 1.先能夠描述任務(wù)(直接使用Runnable)
- 2.需要組織任務(wù)(直接使用BlockingQueue)
- 3.能夠描述工作線程
- 4.還需要組織這些線程
- 5.需要實(shí)現(xiàn)往線程里添加任務(wù)
class MyThreadPool{
//1.先描述一個(gè)任務(wù),直接使用Runnable不需要產(chǎn)生額外類
//2.使用一個(gè)數(shù)據(jù)結(jié)構(gòu)來(lái)組織若干任務(wù)
private BlockingQueue<Runnable> queue= new LinkedBlockingDeque<>();
//3.描述一個(gè)線程,工作線程的功能就是從任務(wù)隊(duì)列中取任務(wù)并執(zhí)行
static class Worker extends Thread{
//當(dāng)前線程池中有若干個(gè)Worker線程,這些線程內(nèi)部都持有了上述的任務(wù)隊(duì)列
private BlockingQueue<Runnable> queue = null;
public Worker(BlockingQueue<Runnable> queue){
this.queue = queue;
}
@Override
public void run() {
//就需要能夠拿到上面的隊(duì)列
while(true){
try {
//循環(huán)的去獲取任務(wù)隊(duì)列中的人物
//這里如果隊(duì)列為空就直接阻塞,如果隊(duì)列非空就獲取到里面的內(nèi)容
Runnable runnable = queue.take();
//獲取到后就執(zhí)行
runnable.run();
} catch (InterruptedException e) {
e.printStackTrace();
}
}
}
}
//4.創(chuàng)建一個(gè)數(shù)據(jù)結(jié)構(gòu)來(lái)組織若干個(gè)線程
private List<Thread> workers = new ArrayList<>();
public MyThreadPool(int n){
//在構(gòu)造方法中創(chuàng)建若干個(gè)線程放到上述數(shù)組中
for (int i = 0; i < n; i++) {
Worker worker = new Worker(queue);
worker.start();
workers.add(worker);
}
}
//5.創(chuàng)建一個(gè)方法,能夠允許程序員來(lái)放任務(wù)到線程池中
public void submit(Runnable runnable){
try {
queue.put(runnable);
} catch (InterruptedException e) {
e.printStackTrace();
}
}
}
public class 我的線程池 {
public static void main(String[] args) {
MyThreadPool pool = new MyThreadPool(10);
for (int i = 0; i < 100; i++) {
pool.submit(new Runnable() {
@Override
public void run() {
System.out.println("hello threadpool");
}
});
}
}
}到此這篇關(guān)于JavaEE線程安全實(shí)現(xiàn)線程池方法的文章就介紹到這了,更多相關(guān)JavaEE線程安全 內(nèi)容請(qǐng)搜索腳本之家以前的文章或繼續(xù)瀏覽下面的相關(guān)文章希望大家以后多多支持腳本之家!
相關(guān)文章
spring AOP自定義注解方式實(shí)現(xiàn)日志管理的實(shí)例講解
下面小編就為大家分享一篇spring AOP自定義注解方式實(shí)現(xiàn)日志管理的實(shí)例講解,具有很好的參考價(jià)值,希望對(duì)大家有所幫助。一起跟隨小編過(guò)來(lái)看看吧2018-01-01
spring定時(shí)器定時(shí)任務(wù)到時(shí)間未執(zhí)行問(wèn)題的解決
這篇文章主要介紹了spring定時(shí)器定時(shí)任務(wù)到時(shí)間未執(zhí)行問(wèn)題的解決,具有很好的參考價(jià)值,希望對(duì)大家有所幫助。如有錯(cuò)誤或未考慮完全的地方,望不吝賜教2021-11-11
Java基于二維數(shù)組實(shí)現(xiàn)的數(shù)獨(dú)問(wèn)題示例
這篇文章主要介紹了Java基于二維數(shù)組實(shí)現(xiàn)的數(shù)獨(dú)問(wèn)題,涉及java針對(duì)數(shù)組的遍歷、計(jì)算、轉(zhuǎn)換等相關(guān)操作技巧,需要的朋友可以參考下2018-01-01
SpringBoot中的自定義FailureAnalyzer詳解
這篇文章主要介紹了SpringBoot中的自定義FailureAnalyzer詳解,FailureAnalyzer是一種很好的方式在啟動(dòng)時(shí)攔截異常并將其轉(zhuǎn)換為易讀的消息,并將其包含在FailureAnalysis中, Spring Boot為應(yīng)用程序上下文相關(guān)異常、JSR-303驗(yàn)證等提供了此類分析器,需要的朋友可以參考下2023-12-12
SpringBoot在IDEA中實(shí)現(xiàn)熱部署的步驟
這篇文章主要介紹了SpringBoot在IDEA中實(shí)現(xiàn)熱部署的步驟,幫助大家更好的理解和使用springboot框架,感興趣的朋友可以了解下2020-11-11

