圖解線程池工作機制,手寫線程池?
ThreadPoolExecutor構造函數的各個參數說明
public ThreadPoolExecutor(int corePoolSize,//線程池中核心線程數
int maximumPoolSize,//允許的最大線程數
long keepAliveTime,//線程空閑下來後,存活的時間,這個參數只在> corePoolSize才有用
TimeUnit unit,//存活時間的單位值
BlockingQueue<Runnable> workQueue,//保存任務的阻塞隊列
ThreadFactory threadFactory,//創建線程的工廠,給新建的線程賦予名字
RejectedExecutionHandler handler) //飽和策略,內置4種策略
AbortPolicy :直接拋出異常,默認;
CallerRunsPolicy:用調用者所在的線程來執行任務
DiscardOldestPolicy:丟棄阻塞隊列裏最老的任務,隊列裏最靠前的任務
DiscardPolicy :當前任務直接丟棄
並允許大佬實現自己的飽和策略,實現RejectedExecutionHandler接口即可。
jdk代碼精選。
步驟一(對應圖1號箭頭,對應源碼第一個if代碼塊): 線程池中線程數 小於corePoolSize ,就會創建新線程。
步驟二(對應圖2號箭頭,對應源碼第二個if代碼塊): 線程池中線程數 等於corePoolSize ,這個任務就會保存到BlockingQueue。
步驟三(對應圖3號箭頭,對應源碼第三個if代碼塊): BlockingQueue也滿了, 線程池中線程數小於 maximumPoolSize時候就會再次創建新的線程。
步驟四(對應圖4號箭頭,對應源碼第三個if代碼塊): BlockingQueue滿了, 線程池中線程數等於 maximumPoolSize時候就會執行飽和策略。
面試官:“談談你對線程池理解”,我:“默默的手寫了一個線程池”,無形裝逼最為致命。
/**
*
*類說明:自己線程池的實現
*/
public class MyThreadPool2 {
// 線程池中默認線程的個數為5
private static int WORK_NUM = 5;
// 隊列默認任務個數為100
private static int TASK_COUNT = 100;
// 工作線程組
private WorkThread[] workThreads;
// 任務隊列,作為一個緩沖
private final BlockingQueue<Runnable> taskQueue;
private final int worker_num;//用戶在構造這個池,希望的啟動的線程數
// 創建具有默認線程個數的線程池
public MyThreadPool2() {
this(WORK_NUM,TASK_COUNT);
}
// 創建線程池,worker_num為線程池中工作線程的個數
public MyThreadPool2(int worker_num,int taskCount) {
if (worker_num<=0) worker_num = WORK_NUM;
if(taskCount<=0) taskCount = TASK_COUNT;
this.worker_num = worker_num;
taskQueue = new ArrayBlockingQueue<>(taskCount);
workThreads = new WorkThread[worker_num];
for(int i=0;i<worker_num;i++) {
workThreads[i] = new WorkThread();
workThreads[i].start();
}
Runtime.getRuntime().availableProcessors();
}
// 執行任務,其實只是把任務加入任務隊列,什麽時候執行有線程池管理器決定
public void execute(Runnable task) {
try {
taskQueue.put(task);
} catch (InterruptedException e) {
e.printStackTrace();
}
}
// 銷毀線程池,該方法保證在所有任務都完成的情況下才銷毀所有線程,否則等待任務完成才銷毀
public void destroy() {
// 工作線程停止工作,且置為null
System.out.println("ready close pool.....");
for(int i=0;i<worker_num;i++) {
workThreads[i].stopWorker();
workThreads[i] = null;//help gc
}
taskQueue.clear();// 清空任務隊列
}
// 覆蓋toString方法,返回線程池信息:工作線程個數和已完成任務個數
@Override
public String toString() {
return "WorkThread number:" + worker_num
+ " wait task number:" + taskQueue.size();
}
/**
* 內部類,工作線程
*/
private class WorkThread extends Thread{
@Override
public void run(){
Runnable r = null;
try {
while (!isInterrupted()) {
r = taskQueue.take();
if(r!=null) {
System.out.println(getId()+" ready exec :"+r);
r.run();
}
r = null;//help gc;
}
} catch (Exception e) {
// TODO: handle exception
}
}
public void stopWorker() {
interrupt();
}
}
}
測試類:
public class TestMyThreadPool extends ThreadPoolExecutor{
public TestMyThreadPool(int corePoolSize, int maximumPoolSize, long keepAliveTime, TimeUnit unit,
BlockingQueue<Runnable> workQueue, RejectedExecutionHandler handler) {
super(corePoolSize, maximumPoolSize, keepAliveTime, unit, workQueue, handler);
// TODO Auto-generated constructor stub
}
public static void main(String[] args) throws InterruptedException {
// 創建3個線程的線程池
MyThreadPool2 t = new MyThreadPool2(3,0);
t.execute(new MyTask("testA"));
t.execute(new MyTask("testB"));
t.execute(new MyTask("testC"));
t.execute(new MyTask("testD"));
t.execute(new MyTask("testE"));
System.out.println(t);
Thread.sleep(10000);
t.destroy();// 所有線程都執行完成才destory
System.out.println(t);
}
// 任務類
static class MyTask implements Runnable {
private String name;
private Random r = new Random();
public MyTask(String name) {
this.name = name;
}
public String getName() {
return name;
}
@Override
public void run() {// 執行任務
try {
Thread.sleep(r.nextInt(1000)+2000);
} catch (InterruptedException e) {
System.out.println(Thread.currentThread().getId()+" sleep InterruptedException:"
+Thread.currentThread().isInterrupted());
}
System.out.println("任務 " + name + " 完成");
}
}
}
圖解線程池工作機制,手寫線程池?