java并发编程面试
文章目錄
- 1.為什么要使用線程池?
- 2.你們哪些地方會使用到線程池?
- 3.線程池有哪些作用?
- 4.線程池的創建方式?
- 5.線程池底層是如何實現復用的?
- 6.ThreadPoolExecutor 核心參數有哪些 ?
- 7.線程池創建的線程會一直在運行狀態嗎?
- 9.線程池底層 ThreadPoolExecutor 底層實現原理
- 10.線程池隊列滿了,任務會丟失嗎 ?
- 11.線程池如何合理配置參數 ?
1.為什么要使用線程池?
因為頻繁的開啟線程或者停止線程, 線程需要重新被 CPU 從就緒到運行狀態調度, 需要發生CPU 的上下文切換, 效率非常低。
2.你們哪些地方會使用到線程池?
實際開發項目中 禁止自己 new 線程,使用線程池來統一維護管理。
案例分享:
項目中異步發郵件和發短信就是用到了多線程,但是呢,我們自己如果通過new thread線程異步的去發短信或者郵件,這樣會存在隱患,導致線程沒有使用到線程池進行維護和統一管理。因此,我們采用線程池的方案,使用springboot整合線程池,實現異步發短信或者郵件。當項目比較小時可以采用此方案,如果,項目比較大做異步時,建議采用使用MQ異步。
3.線程池有哪些作用?
核心點: 復用機制 提前創建好固定的線程一直在運行狀態 實現復用 限制線程創建數量。
1.降低資源消耗: 通過池化技術重復利用已創建的線程, 降低線程創建和銷毀造成的損耗。
2.提高響應速度: 任務到達時, 無需等待線程創建即可立即執行。
3.提高線程的可管理性: 線程是稀缺資源, 如果無限制創建, 不僅會消耗系統資源, 還會因
為線程的不合理分布導致資源調度失衡, 降低系統的穩定性。 使用線程池可以進行統一的分
配、 調優和監控。
4.提供更多更強大的功能: 線程池具備可拓展性, 允許開發人員向其中增加更多的功能。 比
如延時定時線程池 ScheduledThreadPoolExecutor, 就允許任務延期執行或定期執行。
4.線程池的創建方式?
首先線程池的創建方式,我們可以通過JDK原生自帶的方式Executors,提供了4個API,有可緩存線程池、可定長度線程池、可定時線程池、單例線程池;但是非常遺憾,阿里巴巴java開發手冊他不推薦我們使用JDK源碼中自帶的線程池,為什么呢,因為,我們的線程池底層都是基于 ThreadPoolExecutor 構造函數封裝的,而 ThreadPoolExecutor構造函數中,底層都是采用無界隊列緩存我們的任務的,會無限緩存任務容易發生內存溢出,會導致我們最大線程數會失效。
Executors.newCachedThreadPool(); 可緩存線程池
Executors.newFixedThreadPool(); 可定長度 限制最大線程數
Executors.newScheduledThreadPool() ; 可定時
Executors.newSingleThreadExecutor(); 單例
底層都是基于 ThreadPoolExecutor 構造函數封裝
5.線程池底層是如何實現復用的?
本質思想:創建一個線程,不會立馬停止或者銷毀而是一直實現復用。
6.ThreadPoolExecutor 核心參數有哪些 ?
corePoolSize:核心線程數量 一直正在保持運行的線程
maximumPoolSize:最大線程數,線程池允許創建的最大線程數。
keepAliveTime:超出 corePoolSize 后創建的線程的存活時間。
unit:keepAliveTime 的時間單位。
workQueue:任務隊列,用于保存待執行的任務。
threadFactory:線程池內部創建線程所用的工廠。
handler:任務無法執行時的處理器。
7.線程池創建的線程會一直在運行狀態嗎?
不會
例如:配置核心線程數 corePoolSize 為 2 、最大線程數 maximumPoolSize 為 5, 我們可以通過配置超出 corePoolSize 核心線程數后創建的線程的存活時間,例如為 60s, 在 60s 內沒有核心線程一直沒有任務執行,則會停止該線程。
8.為什么阿里巴巴不建議使用 Executors ?
因為默認的 Executors 線程池底層是基于 ThreadPoolExecutor 構造函數封裝的,采用無界隊列存放緩存任務,會無限緩存任務容易發生內存溢出,會導致我們最大線程數會失效。
內存溢出與最大線程數會失效:
源碼中,多線程緩存隊列采用的是LinkedBlockingQueue,而LinkedBlockingQueue的緩存隊列大小是無界的(Integer.MAX_VALUE),緩存隊列中會一直會有新的線程加入進來,當達到服務器的瓶頸時,就會發生內存溢出。最大線程數開啟的前提是緩存隊列容量慢的時候,采用開啟最大線程數。
9.線程池底層 ThreadPoolExecutor 底層實現原理
10.線程池隊列滿了,任務會丟失嗎 ?
11.線程池如何合理配置參數 ?
自定義線程池就需要我們自己配置最大線程數 maximumPoolSize,為了高效的并發運行,當 然這個不能隨便設置。這時需要看我們的業務是 IO 密集型還是 CPU 密集型。
CPU 密集型 CPU 密集的意思是該任務需要大量的運算,而沒有阻塞,CPU 一直全速運行。CPU 密集任 務只有在真正的多核 CPU 上才可能得到加速(通過多線程),而在單核 CPU 上,無論你開幾 個模擬的多線程該任務都不可能得到加速,因為 CPU 總的運算能力就那些。
CPU 密集型任務配置盡可能少的線程數量:以保證每個 CPU 高效的運行一個線程。
一般公式:(CPU 核數+1)個 線程的線程池
IO 密集型
I0 密集型,即該任務需要大量的 IO,即大量的阻塞。在單線程上運行 I0 密集型的任務會導 致浪費大量的 CPU 運算能力浪費在等待。 所以在 IO 密集型任務中使用多線程可以大大的加速程序運行,即使在單核 CPU 上,這種加 速主要就是利用了被浪費掉的阻塞時間。
I0 密集型時,大部分線程都阻寒,故需要多配置線程數:
公式: CPU 核數 * 2 CPU 核數 / (1 - 阻塞系數) 阻塞系數 在 0.8~0.9 之間
查看 CPU 核數: System.out.println(Runtime.getRuntime().availableProcessors());
總結
以上是生活随笔為你收集整理的java并发编程面试的全部內容,希望文章能夠幫你解決所遇到的問題。
- 上一篇: IntelliJ IDEA 导入项目后出
- 下一篇: 移动端小程序 腾讯地图sdk 当前位置