自拍偷在线精品自拍偷,亚洲欧美中文日韩v在线观看不卡

面試被問線程池,真香

開發(fā) 前端
說到并發(fā)編程,怎么少的了線程池,在阿里線程池使用場景非常多,用好線程池這個利器也算是日常開發(fā)必須掌握的了,下面講講2019年的那一夜,就線程池和某位面試官鏖戰(zhàn)了半個小時。

[[380809]]

本文轉(zhuǎn)載自微信公眾號「安琪拉的博客」,作者安琪拉的博客 。轉(zhuǎn)載本文請聯(lián)系安琪拉的博客公眾號。

這篇是并發(fā)編程系列文章第五篇了,說到并發(fā)編程,怎么少的了線程池,在阿里線程池使用場景非常多,用好線程池這個利器也算是日常開發(fā)必須掌握的了,下面講講2019年的那一夜,就線程池和某位面試官鏖戰(zhàn)了半個小時。

面試官 : 看你簡歷上寫了對系統(tǒng)性能做了優(yōu)化,能簡單給我介紹一下嗎?都有哪些優(yōu)化,你是怎么衡量優(yōu)化效果的?

我 : 巴拉巴拉。。。例如我們系統(tǒng)之前要查詢用戶的個人身份信息、聯(lián)系人信息、訂單狀態(tài)信息、積分信息,之前系統(tǒng)是單線程串行處理的,我用線程池對四個任務(wù)并行處理,然后對處理結(jié)果合并。

面試官 : 你剛才說用到線程池,能跟我講講為什么用線程池嗎?我創(chuàng)建四個線程處理可不可以?

我 : 可以,當然可以。

我 : 但是用線程池更合適。阿里巴巴開發(fā)規(guī)約中有一條:

3.【強制】線程資源必須通過線程池提供,不允許在應用中自行顯式創(chuàng)建線程。

說明:使用線程池的好處是減少在創(chuàng)建和銷毀線程上所消耗的時間以及系統(tǒng)資源的開銷,解決資源不足的問題。如果不使用線程池,有可能造成系統(tǒng)創(chuàng)建大量同類線程而導致消耗完內(nèi)存或者“過度切換”的問題。

《阿里巴巴研發(fā)手冊》

我 : 就像你去餐廳吃飯,服務(wù)員總是提前洗好盤子,不會等你來打飯的時候才洗盤子,盤子就像是線程池里的線程,你打飯就是要處理的任務(wù)。

面試官 : 那你知道線程池的相關(guān)類關(guān)系嗎?

我: 這算什么問題?不應該是問我核心線程數(shù)怎么設(shè)置嗎?好吧。。。請看下圖:

  • Executor 的定義非常簡單,就定義了線程池最本質(zhì)要做的事,執(zhí)行任務(wù)。
  1. public interface Executor { 
  2.  
  3.     void execute(Runnable command); 
  • ExecutorService 也是個接口,不過他算是把線程池的框架搭出來了,告訴要實現(xiàn)它的線程池必須提供的一些管理線程池的方法。
  • AbstractExecutorService 是普通的線程池執(zhí)行器,ScheduledExecutorService 是定時任務(wù)線程池。

面試官 : 那你日常開發(fā)中是怎么創(chuàng)建線程池的?

我: 我用ThreadPoolExecutor 自定義創(chuàng)建線程池。

面試官 : 那你知道線程池都有哪些核心參數(shù)嗎?

我: 線程池主要的核心參數(shù)有7個,我們看 ThreadPoolExecutor 構(gòu)造函數(shù)就知道了

  • corePoolSize :核心線程數(shù)
  • maximumPoolSize: 最大線程數(shù)
  • keepAliveTime :線程在線程池中不被銷毀的空閑時間,如果線程池的線程太多,任務(wù)比較小,到這個時間就銷毀線程池。
  • unit : keepAliveTime 的時間單位,一般設(shè)置成秒或毫秒。
  • workQueue : 任務(wù)隊列,存放等待執(zhí)行的任務(wù)
  • threadFactory: 創(chuàng)建線程的任務(wù)工廠,比如給線程命名加上前綴,后面會講
  • handler : 拒絕任務(wù)處理器,當任務(wù)處理不過來時的拒絕處理器
  • allowCoreThreadTimeOut : 是否允許核心線程超時銷毀,這個參數(shù)不在構(gòu)造函數(shù)中,但重要性也很高

面試官 : 老實說,你是不是來之前背過了,不然怎么可能都記住了。

我: [掀桌子],不面了,還找什么工作,要什么自行車。

我不過是來之前把“安琪拉的博客”公眾號上的文章都看了個遍。

面試官 : 其實剛才那也是問題,考察面試者是否皮實,我們繼續(xù)。。

面試官 : 剛才說了這些核心參數(shù),你能不能跟我講講線程池的基本工作原理。

我: 可以的,這里我給你畫個流程,如下所示:

面試官 : 那按照上面的流程寫段偽代碼。

我: 還能不能好好面了,讓手撕線程池。

那好吧,你對著的流程圖看,代碼如下:

面試官 : 不錯,那你平常怎么管理線程池的呢?

我: 我會搞了個線程池管理器,比如 ThreadPoolManager,有個私有變量的Map,按照線程池的作用給他取個名字,比如起名為: preparePlateThreadPool (準備餐盤線程池),把線程池名稱定義成常量,和創(chuàng)建好的線程池放到管理器的Map里。

面試官 : 除了你自己用 ThreadPoolExecutor 創(chuàng)建線程池,還有別的方式嗎?

我: java.util.concurrent 包里提供的 Executors 也可以用來創(chuàng)建線程池。

面試官 : Executors 定義了哪幾種 ?

我:

  • newSingleThreadExecutos 單線程線程池,也就是線程池只有一個任務(wù),這個我偶爾用一用
  • newFixedThreadPool(int nThreads) 固定大小線程的線程池
  • newCachedThreadPool() 無界線程池,這個就是無論多少任務(wù),都創(chuàng)建線程來運行,所以隊列相當于沒用。

面試官 : 你上面講日常開發(fā)自己 用 ThreadPoolExecutor 創(chuàng)建線程池,為什么不用Executors 提供的。

我: 第一是 Executors 提供的線程池使用場景很有限,一般場景很難用到,第二他們也都是通過 ThreadPoolExecutor 創(chuàng)建的線程池,我直接用 ThreadPoolExecutor 創(chuàng)建線程池,可以理解原理,靈活度更高。

參考阿里開發(fā)手冊規(guī)約:

4.【強制】線程池不允許使用Executors去創(chuàng)建,而是通過ThreadPoolExecutor的方式,這樣的處理方式讓寫的同學更加明確線程池的運行規(guī)則,規(guī)避資源耗盡的風險。

說明:Executors返回的線程池對象的弊端如下:

1)FixedThreadPool和SingleThreadPool:

  • 允許的請求隊列長度為Integer.MAX_VALUE,可能會堆積大量的請求,從而導致OOM。

2)CachedThreadPool:

  • ??允許的創(chuàng)建線程數(shù)量為Integer.MAX_VALUE,可能會創(chuàng)建大量的線程,從而導致OOM。

《阿里巴巴研發(fā)手冊》

面試官 : 前面你代碼里有任務(wù)入隊的操作,你一般自定義線程池,用的什么隊列?

我: 這個要看實際應用的。

  • 有的任務(wù)在早上8點和晚上6點都是高峰期,因此有任務(wù)尖刺,用 LinkedBlockingQueue, 這個是無界隊列,不限制任務(wù)大小的。
  • 對于重要性沒那么高,非強依賴的任務(wù)用的ArrayBlockingQueue,這個是指定大小的,如果任務(wù)超出,會創(chuàng)建非核心線程執(zhí)行任務(wù)。

面試官 : 那你怎么保證任務(wù)隊列的可用性呢?

我: 分幾個方面:

  1. 我的線程池管理器,會有一個定時任務(wù),定時檢測Map 中線程池當前任務(wù)隊列的狀態(tài),會設(shè)置一個 waterThreshold(水位線),超出水位線會有告警;
  2. 日常大促演練,會對線程池做壓測,如果發(fā)生超水位情況,還會對線程按線程名做降級,動態(tài)調(diào)整核心線程數(shù)和隊列,當然還有限流、降級等其他有段保障。

面試官 : 那你怎么合理拆分線程池,核心任務(wù)數(shù)和任務(wù)隊列大小的呢?

我: 這個是個老生常談的問題。

【推薦】 了解每個服務(wù)大致的平均耗時,可以通過獨立線程池配置,將較慢的服務(wù)與主線程池隔離開,不致于各服務(wù)線程同歸于盡。

《阿里巴巴研發(fā)手冊》

  • 按照任務(wù)的類型,對任務(wù)做拆分,分成不同的線程池,分別命名;
  • 區(qū)分任務(wù)的類型,是CPU密集型還是IO密集型,CPU 可以設(shè)置約為CPU核心數(shù),上下文切換少,io密集型可以設(shè)置的大一些。
  • 大體估算一個,然后做壓測,評估,另外線程池有個變量也可以參考意義:largestPoolSize,線程池達到過的最大線程任務(wù),比如你剛開始可以把線程數(shù)設(shè)置的足夠大,壓測過后看這個參數(shù)達到的最大數(shù)值,同時參考系統(tǒng)的性能指標,cou、io、mem等。

這里還有個公式借鑒:最佳線程數(shù)目 = ((線程等待時間+線程CPU時間)/線程CPU時間 )* CPU數(shù)目

也有開源的輔助測算線程池的合理線程數(shù)。

面試官 : 那拒絕策略呢?了解嗎

我: 拒絕策略就是當任務(wù)太多,超過maximumPoolSize了,只能拒絕。

面試官 : 詳細講講

我: 拒絕的時候可以指定拒絕策略,也可以自己實現(xiàn),JDK默認提供了四種拒絕策略.

  • AbortPolicy

默認拒絕策略, 直接拋RejectedExecutionException

  • DiscardPolicy

任務(wù)直接丟棄,不拋出異常

  • CallerRunsPolicy

由調(diào)用者來執(zhí)行被拒絕的任務(wù),比如主線程調(diào)用線程池的submit提交任務(wù),但是任務(wù)被拒絕,則主線程直接執(zhí)行。

但是線程池如果已經(jīng)被關(guān)閉了,任務(wù)就被丟棄了。

  1. public void rejectedExecution(Runnable r, ThreadPoolExecutor e) { 
  2. //線程池沒關(guān)閉 
  3. if (!e.isShutdown()) { 
  4. //直接run,沒有讓線程池來執(zhí)行 
  5.   r.run(); 
  • DiscardOldestPolicy

丟棄隊列里等的最久的任務(wù),然后嘗試執(zhí)行被拒絕的任務(wù)。

但是線程池如果已經(jīng)被關(guān)閉了,任務(wù)就被丟棄了

  1. public void rejectedExecution(Runnable r, ThreadPoolExecutor e) { 
  2. if (!e.isShutdown()) { 
  3.   //丟棄隊列頭部任務(wù) 
  4.   e.getQueue().poll(); 
  5.   //線程池嘗試執(zhí)行任務(wù) 
  6.   e.execute(r); 
  7. 面試官 :  那這幾種拒 

面試官 : 那這幾種拒絕策略,你選哪一種?

我: 我選拒絕回答

面試官 : 我選你回去等通知。

到年底了,螞蟻現(xiàn)在有些崗位放出來,有挑戰(zhàn)的業(yè)務(wù)場景,6位數(shù)QPS,流程加快,拿完年終,過完年直接來上班,這個點競爭壓力小。

不管想不想來都可以來找我聊聊,我的微信: guofu-angela。

 

責任編輯:武曉燕 來源: 安琪拉的博客
相關(guān)推薦

2020-02-18 14:25:51

Java線程池拒絕策略

2024-01-12 10:05:32

線程池代碼

2022-03-22 09:20:57

應用線程池技術(shù)

2023-08-15 15:33:29

線程池線程數(shù)

2025-04-23 08:10:00

2023-12-18 08:03:56

并發(fā)編程Java

2021-04-13 10:41:25

Redis內(nèi)存數(shù)據(jù)庫

2023-01-29 08:04:24

線程池非核心線程任務(wù)

2021-06-01 10:49:22

線程池Java開發(fā)

2021-06-03 14:23:57

線程線程池JAVA

2019-12-19 09:23:45

Java多線程數(shù)據(jù)

2024-04-02 09:45:27

線程池Executors開發(fā)

2022-03-02 07:36:37

池化技術(shù)Java線程池

2023-09-26 08:36:31

ES6 模塊JS 題目

2024-09-09 15:09:30

2024-03-11 18:18:58

項目Spring線程池

2020-09-16 12:29:03

線程池任務(wù)函數(shù)

2023-10-17 16:30:00

TCP

2021-03-29 08:47:24

線程面試官線程池

2024-11-11 00:00:01

線程池工具
點贊
收藏

51CTO技術(shù)棧公眾號