面試官:線程池的工作原理是啥?能手寫一個線程池嗎?

面試官:線程池的工作原理是啥?能手寫一個線程池嗎?

為什麼要有線程池這個東西?

創建線程對象不像其他對象一樣在JVM分配內存即可,還要調用操作系統內核的API,然後操作系統為線程分配一系列的資源,這個成本就很高了。所以線程是一個重量級對象,應該避免頻繁創建和銷燬

再說一下線程池的大概工作流程

以前我們運行線程的時候new Thread().start()即可,如果線程數多了,頻繁的創建線程和銷燬線程很費時間。

然後Doug Lea就這樣設計了一下,預先啟動幾個線程,還準備好一個容器。每次想執行任務時,就將實現了Runnable接口的任務放到這個容器中,預先啟動好的線程不斷從容器中拿出任務,調用執行Runnable接口的run方法,這樣剛開始啟動的線程就能執行很多次任務。大概流程就是這樣,真正的線程池考慮的東西比較多。

想到沒有,這就是典型的生產者-消費者模式,線程池的使用者是生產者,線程池本身是消費者。用代碼來實現一下

面試官:線程池的工作原理是啥?能手寫一個線程池嗎?

驗證代碼(正常工作)

面試官:線程池的工作原理是啥?能手寫一個線程池嗎?

來看一下Java中的線程池類ThreadPoolExecutor的構造函數有哪些參數?

<code>public ThreadPoolExecutor
(int corePoolSize,
int maximumPoolSize,
long keepAliveTime,
TimeUnit unit,
BlockingQueue<runnable> workQueue,
ThreadFactory threadFactory,
RejectedExecutionHandler handler)/<runnable>/<code>

來類比學習一下這些參數,我們把

線程池類比為項目組,線程是這個公司的成員

corePoolSize:線程池中最少的線程數,一個項目組總得有corePoolSize人堅守陣地,都是簽訂勞動合同了,不能隨便撤。

maximumPoolSize:當項目很忙時,就得加人,請其他項目組的人來幫忙。但是公司空間有限,最多隻能加到maximumPoolSize個人。當項目閒了,就得撤人了,最多能撤到corePoolSize個人

keepAliveTime & unit:上面提到項目根據忙閒來增減人員,那在編程世界裡,如何定義忙和閒呢?如果一個線程在keepAliveTime(時間數字)* unit(時間單位)時間內都沒有執行任務,說明這個線程很閒。如果此時線程數大於corePoolSize,這個線程就要被回收了

workQueue:就是任務隊列

threadFactory:自定義如果創建線程,例如給線程指定一個有意義的名字

handler:workQueue滿了(排期滿了),再提交任務,該怎麼處理呢?這個就是處理策略,線程池提供了4種策略,你也可以實現RejectedExecutionHandler接口來自定義策略

面試官:線程池的工作原理是啥?能手寫一個線程池嗎?

現在你可以去看看jdk提供的ThreadPoolExecutor類,發現原來也沒那麼難理解,為了方便大家練習,我把可以粘貼的代碼放上來,方便大家粘貼

<code>public class MyThreadPool {

/** 利用阻塞隊列實現生產者-消費者模式 */
BlockingQueue<runnable> workQueue;

/** 保存內部工作線程 */
List<workthread> workThreadList = new ArrayList<>();
MyThreadPool(int poolSize, BlockingQueue<runnable> workQueue) {
this.workQueue = workQueue;
for (int i = 0; i < poolSize; i++) {
WorkThread workThread = new WorkThread();
workThread.start();
workQueue.add(workThread);
}
}

void execute(Runnable command) {
// 放入任務,如果沒有空間,則阻塞等待
// try catch部分省略
workQueue.put(command);
}

class WorkThread extends Thread {
@Override
public void run() {
// 循環取任務並執行
while (true) {
Runnable task = null;
// 獲取阻塞隊列的第一個任務,並刪除
// 如果沒有元素,則會阻塞等待
// try catch部分省略
task = workQueue.take();
task.run();

}
}
}

public static void main(String[] args) {
BlockingQueue<runnable> workQueue = new LinkedBlockingQueue<>(5);
MyThreadPool pool = new MyThreadPool(2, workQueue);
for (int i = 0; i < 10; i++) {
int num = i;
pool.execute(()->{
System.out.println("線程 " + num + " 執行");
});
}
}

}/<runnable>/<runnable>/<workthread>/<runnable>/<code>

Java面試手冊

目錄

一、性能優化面試專欄

1.1、tomcat性能優化整理

1.2、JVM性能優化整理

1.3、Mysql性能優化整理

二、微服務架構面試專欄

2.1、SpringCloud面試整理

2.2、SpringBoot面試整理

2.3、Dubbo面試整理

面試官:線程池的工作原理是啥?能手寫一個線程池嗎?

三、併發編程高級面試專欄

四、開源框架面試題專欄

4.1、Spring面試整理

4.2、SpringMVC面試整理

4.3、MyBatis面試整理

五、分佈式面試專欄

5.1、分佈式限流面試整理

5.2、分佈式通訊面試整理

5.3、分佈式數據庫面試整理

面試官:線程池的工作原理是啥?能手寫一個線程池嗎?

面試官:線程池的工作原理是啥?能手寫一個線程池嗎?

面試官:線程池的工作原理是啥?能手寫一個線程池嗎?

面試官:線程池的工作原理是啥?能手寫一個線程池嗎?

面試官:線程池的工作原理是啥?能手寫一個線程池嗎?

有需要獲取面試體系文檔的朋友可以轉發文章並關注作者,然後私信回覆“Java面試”即可獲得以上所有面試PDF文檔資料的領取方式!以前沒獲取到的粉絲或者小夥伴們都可以獲取參考哦

如何獲取?

轉發這篇文章,關注我,私信回覆“java面試”即可獲取高清大綱,以上 spring,MyBatis,Netty源碼分析,高併發、高性能、分佈式、微服務架構的原理,JVM性能優化、分佈式架構

如何私信?

關注我後,在手機,點進頭像進我的主頁,主頁上方右上角有個私信,點擊私信,如何回覆關鍵字“java面試”即可


分享到:


相關文章: