學生視角手把手帶你寫Java?線程池初版
Java手寫線程池(第一代)
經(jīng)常使用線程池,故今天突發(fā)奇想,手寫一個線程池,會有很多不足,請多多寬容。因為這也是第一代的版本,后續(xù)會更完善。
手寫線程池-定義參數(shù)
private final AtomicInteger taskcount=new AtomicInteger(0); private final AtomicInteger threadNumber=new AtomicInteger(0); private volatile int corePoolSize; private final Set<MyThreadPoolExecutor.MyWorker> workers; private final BlockingQueue<Runnable> waitingQueue; private final String THREADPOOL_NAME="MyThread-Pool-"; private volatile boolean isRunning=true; private volatile boolean STOPNOW=false; private final ThreadFactory threadFactory;
- taskcount:執(zhí)行任務(wù)次數(shù)
- threadNumber:線程編號,從0開始依次遞增。
- corePoolSize:核心線程數(shù)
- workers:工作線程
- waitingQueue:等待隊列
- THREADPOOL_NAME:線程名稱
- isRunning:是否運行
- STOPNOW:是否立刻停止
- threadFactory:線程工廠
手寫線程池-構(gòu)造器
public MyThreadPoolExecutor(int corePoolSize, BlockingQueue<Runnable> waitingQueue,ThreadFactory threadFactory) { this.corePoolSize=corePoolSize; this.workers=new HashSet<>(corePoolSize); this.waitingQueue=waitingQueue; this.threadFactory=threadFactory; //線程預(yù)熱 for (int i = 0; i < corePoolSize; i++) { new MyWorker(); } }
該構(gòu)造器作用:
1:對參數(shù)進行賦值。
2:線程預(yù)熱。根據(jù)corePoolSize的大小來調(diào)用MyWorker的構(gòu)造器。我們可以看看MyWorker構(gòu)造器做了什么。
final Thread thread; //為每個MyWorker MyWorker(){ Thread td = threadFactory.newThread(this); td.setName(THREADPOOL_NAME+threadNumber.getAndIncrement()); this.thread=td; this.thread.start(); workers.add(this); }
- MyWorker構(gòu)造器通過線程工廠對當前對象生成Thread;
- 并設(shè)置線程名為:MyThread-Pool-自增線程編號;
- 然后調(diào)用線程的start方法啟動線程;
- 最后存放在workers這個Set集合中,這樣就可以實現(xiàn)線程復(fù)用了。
手寫線程池-默認構(gòu)造器
public MyThreadPoolExecutor(){ this(5,new ArrayBlockingQueue<>(10), Executors.defaultThreadFactory()); }
- 默認構(gòu)造器的賦初始值:
- corePoolSize:5
- waitingQueue:new ArrayBlockingQueue<>(10),長度為10的有限阻塞隊列
- threadFactory:Executors.defaultThreadFactory()
手寫線程池-execute方法
public boolean execute(Runnable runnable) { return waitingQueue.offer(runnable); }
- 本質(zhì)上其實就是把Runnable(任務(wù))放到waitingQueue中。
手寫線程池-處理任務(wù)
@Override public void run() { //循環(huán)接收任務(wù) while (true) { if((!isRunning&&waitingQueue.size()==0)||STOPNOW) { break; }else { Runnable runnable = waitingQueue.poll(); if(runnable!=null){ runnable.run(); System.out.println("task==>"+taskcount.incrementAndGet()); } } } }
本質(zhì)上就是一個死循環(huán)接收任務(wù),退出條件如下:
- 優(yōu)雅的退出。當isRunning為false并且waitingQueue的隊列大小為0(也就是無任務(wù)了)
- 暴力退出。當STOPNOW為true,則說明調(diào)用了shutdownNow方法
- else語句塊會不斷取任務(wù),當任務(wù)!=null時則調(diào)用run方法處理任務(wù)
手寫線程池-優(yōu)雅關(guān)閉線程池
public void shutdown() { this.isRunning=false; }
手寫線程池-暴力關(guān)閉線程池
public void shutdownNow() { this.STOPNOW=true; }
手寫線程池-源代碼
- 手寫線程池類的源代碼
package com.springframework.concurrent; import java.util.HashSet; import java.util.Set; import java.util.concurrent.ArrayBlockingQueue; import java.util.concurrent.BlockingQueue; import java.util.concurrent.Executors; import java.util.concurrent.ThreadFactory; import java.util.concurrent.atomic.AtomicInteger; /** * 線程池類 * @author 游政杰 */ public class MyThreadPoolExecutor { private final AtomicInteger taskcount=new AtomicInteger(0);//執(zhí)行任務(wù)次數(shù) private final AtomicInteger threadNumber=new AtomicInteger(0); //線程編號 private volatile int corePoolSize; //核心線程數(shù) private final Set<MyThreadPoolExecutor.MyWorker> workers; //工作線程 private final BlockingQueue<Runnable> waitingQueue; //等待隊列 private final String THREADPOOL_NAME="MyThread-Pool-";//線程名稱 private volatile boolean isRunning=true; //是否運行 private volatile boolean STOPNOW=false; //是否立刻停止 private final ThreadFactory threadFactory; //線程工廠 public MyThreadPoolExecutor(){ this(5,new ArrayBlockingQueue<>(10), Executors.defaultThreadFactory()); } public MyThreadPoolExecutor(int corePoolSize, BlockingQueue<Runnable> waitingQueue,ThreadFactory threadFactory) { this.corePoolSize=corePoolSize; this.workers=new HashSet<>(corePoolSize); this.waitingQueue=waitingQueue; this.threadFactory=threadFactory; //線程預(yù)熱 for (int i = 0; i < corePoolSize; i++) { new MyWorker(); } } /** * MyWorker就是我們每一個線程對象 */ private final class MyWorker implements Runnable{ final Thread thread; //為每個MyWorker MyWorker(){ Thread td = threadFactory.newThread(this); td.setName(THREADPOOL_NAME+threadNumber.getAndIncrement()); this.thread=td; this.thread.start(); workers.add(this); } @Override public void run() { //循環(huán)接收任務(wù) while (true) { //循環(huán)退出條件: //1:當isRunning為false并且waitingQueue的隊列大小為0(也就是無任務(wù)了),會優(yōu)雅的退出。 //2:當STOPNOW為true,則說明調(diào)用了shutdownNow方法進行暴力退出。 if((!isRunning&&waitingQueue.size()==0)||STOPNOW) { break; }else { //不斷取任務(wù),當任務(wù)!=null時則調(diào)用run方法處理任務(wù) Runnable runnable = waitingQueue.poll(); if(runnable!=null){ runnable.run(); System.out.println("task==>"+taskcount.incrementAndGet()); } } } } } public boolean execute(Runnable runnable) { return waitingQueue.offer(runnable); } //優(yōu)雅的關(guān)閉 public void shutdown() { this.isRunning=false; } //暴力關(guān)閉 public void shutdownNow() { this.STOPNOW=true; } }
- 測試使用手寫線程池代碼
package com.springframework.test; import com.springframework.concurrent.MyThreadPoolExecutor; import java.util.concurrent.ArrayBlockingQueue; import java.util.concurrent.Executors; public class ThreadPoolTest { public static void main(String[] args) { MyThreadPoolExecutor myThreadPoolExecutor = new MyThreadPoolExecutor (5,new ArrayBlockingQueue<>(6), Executors.defaultThreadFactory()); for(int i=0;i<10;i++){ int finalI = i; myThreadPoolExecutor.execute(()->{ System.out.println(Thread.currentThread().getName()+">>>>"+ finalI); }); } myThreadPoolExecutor.shutdown(); // myThreadPoolExecutor.shutdownNow(); } }
問題
為什么自定義線程池的execute執(zhí)行的任務(wù)有時會變少?
那是因為waitingQueue滿了放不下任務(wù)了,導致任務(wù)被丟棄,相當于DiscardPolicy拒絕策略
解決辦法有:
1:設(shè)置最大線程數(shù),自動對線程池擴容。
2:調(diào)大waitingQueue的容量capacity
最后:因為這是我手寫的線程池的初代版本,基本實現(xiàn)線程池的復(fù)用功能,然而還有很多未完善,將來會多出幾篇完善后的文章,對目前手寫的線程池進行升級。
后續(xù)還會繼續(xù)出關(guān)于作者手寫Spring框架,手寫Tomcat等等框架的博文?。。。?!
到此這篇關(guān)于學生視角手把手帶你寫Java 線程池的文章就介紹到這了,更多相關(guān)Java 線程池內(nèi)容請搜索腳本之家以前的文章或繼續(xù)瀏覽下面的相關(guān)文章希望大家以后多多支持腳本之家!
相關(guān)文章
java代碼實現(xiàn)mysql分表操作(用戶行為記錄)
這篇文章主要介紹了java代碼實現(xiàn)mysql分表操作(用戶行為記錄),具有很好的參考價值,希望對大家有所幫助。一起跟隨小編過來看看吧2021-02-02Java應(yīng)用多機器部署解決大量定時任務(wù)問題
這篇文章主要介紹了Java應(yīng)用多機器部署解決大量定時任務(wù)問題,兩臺服務(wù)器同時部署了同一套代碼, 代碼中寫有spring自帶的定時任務(wù),但是每次執(zhí)行定時任務(wù)時只需要一臺機器去執(zhí)行,需要的朋友可以參考下2019-07-07Java Fluent Mybatis 分頁查詢與sql日志輸出詳解流程篇
Java中常用的ORM框架主要是mybatis, hibernate, JPA等框架。國內(nèi)又以Mybatis用的多,基于mybatis上的增強框架,又有mybatis plus和TK mybatis等。今天我們介紹一個新的mybatis增強框架 fluent mybatis關(guān)于分頁查詢、sql日志輸出流程2021-10-10JVM內(nèi)存結(jié)構(gòu)相關(guān)知識解析
這篇文章主要介紹了JVM內(nèi)存結(jié)構(gòu)相關(guān)知識解析,文中通過示例代碼介紹的非常詳細,對大家的學習或者工作具有一定的參考學習價值,需要的朋友可以參考下2019-11-11Java util.List如何實現(xiàn)列表分段處理
這篇文章主要介紹了Java util.List如何實現(xiàn)列表分段處理,文中通過示例代碼介紹的非常詳細,對大家的學習或者工作具有一定的參考學習價值,需要的朋友可以參考下2020-09-09