偷偷摘套内射激情视频,久久精品99国产国产精,中文字幕无线乱码人妻,中文在线中文a,性爽19p

被開發(fā)者拋棄的 Executors,錯在哪兒?

開發(fā) 后端
日常開發(fā)中,應(yīng)該收緊對線程池的創(chuàng)建,由開發(fā)人員明確線程池的運行規(guī)則,以此來盡量規(guī)避其資源耗盡的風(fēng)險。線程池是個好東西,但是怎么創(chuàng)建是一個問題。

一、序

在 Java 領(lǐng)域內(nèi),我們使用多線程的方式來實現(xiàn)并發(fā)編程。而線程本身是操作系統(tǒng)的一個概念,雖然不同的語言對線程都進行了一些封裝,但是最終都是調(diào)用到操作系統(tǒng)中去創(chuàng)建和調(diào)度線程。

既然線程是一項重要的系統(tǒng)資源,為了更合理的利用此資源,我們會使用池化技術(shù)來優(yōu)化線程的創(chuàng)建和銷毀,這就是線程池。

[[314821]]

在我們學(xué)習(xí)并發(fā)編程的時候,線程可以利用 Thread 來創(chuàng)建并通過 start() 來啟動一個線,但在成熟的項目中,基本上是不允許這樣操作線程的,都需要通過線程池去收斂線程的使用,所以線程池是必須的。

Java 的線程池可以通過 ThreadPoolExecutor 來構(gòu)造,在其中提供非常完備的構(gòu)造方法,可以根據(jù)我們的業(yè)務(wù)需求靈活的構(gòu)造線程池。同時 Java 還提供了一個 Executors,它內(nèi)部提供了很多包裝的方法,利用它可以幫我們快速的構(gòu)建線程池。

原本 Executors 的目的就是為了讓我們更方便的使用線程池,但是《阿里巴巴Java開發(fā)手冊》也明確指出,直接使用 Executors 的缺陷。

手冊中提到強制不允許使用 Executors 去創(chuàng)建線程池,而是應(yīng)該使用退化到最原始的 ThreadPoolExecutor 的方式。

被開發(fā)者拋棄的 Executors,錯在哪兒?

日常開發(fā)中,應(yīng)該收緊對線程池的創(chuàng)建,由開發(fā)人員明確線程池的運行規(guī)則,以此來盡量規(guī)避其資源耗盡的風(fēng)險。

線程池是個好東西,但是怎么創(chuàng)建是一個問題。

二、Executors 怎么了?

1. 不被允許的 Executors

不應(yīng)該使用 Executors 的原因,其實《阿里巴巴Java開發(fā)手冊》里已經(jīng)寫明了,當(dāng)需要處理大量任務(wù)的時候,可能會出現(xiàn) OOM 異常,但它們出現(xiàn) OOM 的原因并不一樣。

ThreadPoolExecutor 的構(gòu)造方法中,提供了很多參數(shù)的配置,其中與 Executors 出現(xiàn) OOM 相關(guān)的就有 2 個:核心線程數(shù)和等待隊列。

先來看看 FixedThreadPool 和 SingleThreadPool 出現(xiàn) OOM 的原因。

它們的問題在于等待隊列使用了 LinkedBlockingQueue 這個以鏈表實現(xiàn)的無界隊列(最大長度是 Integer.MAX_VALUE),最終導(dǎo)致堆積了大量等待處理的任務(wù),從而導(dǎo)致頻繁的 GC,最終觸發(fā) OOM。

  1. java.lang.OutOfMemoryError: GC overhead limit exceeded 

再來看看 CachedThreadPool 出現(xiàn) OOM 的原因。

它的問題在于核心線程數(shù)設(shè)置為了 Integer.MAX_VALUE,并且等待隊列是一個 SynchronousQueue。

SynchronousQueue 是一個沒有數(shù)據(jù)緩沖的阻塞隊列,它極易被阻塞。在等待隊列被阻塞的時候,如果線程數(shù)量還沒有達到核心線程數(shù)限制的數(shù)量時,線程池的策略是創(chuàng)建新的線程來處理新的任務(wù)。

也就是說,是核心線程數(shù)和等待隊列 SynchronousQueue 合力造成了線程會跟隨任務(wù)不斷的被創(chuàng)建,直到觸發(fā) OOM。

  1. java.lang.OutOfMemoryError: pthread_creat (1040KB stack) failed: Try again 

ScheduledThreadPool 的等待隊列使用的是 DelayedWorkQueue,原理也是類似的,最終會導(dǎo)致創(chuàng)建大量的線程而拋出 OOM。

線程是一種系統(tǒng)資源,本身創(chuàng)建就會帶來內(nèi)存開銷,同時操作系統(tǒng)對單進程可創(chuàng)建的線程數(shù)也是有限制的。

在 Android 中,每個線程初始化都需要 mmap 一定的堆內(nèi)存,在默認的情況下,初始化一個線程大約需要 mmap 1MB 左右的內(nèi)存空間。同時系統(tǒng)本身也會對每個進程可創(chuàng)建的線程數(shù),做一定的限制,這個限制在 /proc/pid/limits 中,不同的廠商對這個限制也有所不同,當(dāng)超出限制時,哪怕堆上還有可用內(nèi)存,依然會拋出 OOM。

2. Executors 錯在哪兒了?

Executors 會在任務(wù)過多的時候,導(dǎo)致資源耗盡而觸發(fā) OOM,這是它帶來的危害。

Executors 最大的問題,在于沒有邊界。

在系統(tǒng)環(huán)境良好,任務(wù)不多的時候 Executors 創(chuàng)建的線程池,都是可以正常工作的。

但是一旦有重壓,我們就無法預(yù)知什么時候會出現(xiàn)問題,這就是沒有邊界,沒有邊界就意味著不可控。

我們很難去信任一段不可控的代碼,它什么時候出現(xiàn)問題,完全是不可預(yù)知的,這才是 Executors 最大的問題。

除此之外,Executors 封裝了太多線程池的細節(jié),本身也不建議使用。例如通常我們需要給線程池創(chuàng)建的線程,起一個有意義的名稱,方便在出現(xiàn)異常的時候排查問題;再例如對與線程池的拒絕策略,我們需要深思熟慮的定義,是直接拋棄還是持久化下來延遲處理。

去思考一個線程池的不同參數(shù)帶來的策略細節(jié),才是使用線程池的一個良好的開發(fā)習(xí)慣。

三. 小結(jié)時刻

本文我們聊了關(guān)于創(chuàng)建線程池,使用 Executors 創(chuàng)建的線程池會有 OOM 的風(fēng)險,應(yīng)該使用 ThreadPoolExecutor 去創(chuàng)建線程池。通過思考業(yè)務(wù)來明確配置線程池不同的參數(shù),例如線程池、等待隊列、拒絕策略等等。

責(zé)任編輯:趙寧寧 來源: 承香墨影
相關(guān)推薦

2020-02-11 17:15:09

開發(fā)者拋棄 Executors

2014-04-29 14:52:06

大數(shù)據(jù)

2011-12-12 13:09:45

云計算

2015-08-27 13:45:25

2023-09-12 11:38:18

2019-07-23 16:00:36

區(qū)塊鏈存儲5G

2022-02-25 10:03:11

對象數(shù)據(jù)算法

2015-10-23 11:40:08

SaaS應(yīng)用開發(fā)

2013-12-04 09:33:15

軟件成本

2014-04-17 10:16:50

2013-05-10 10:58:56

ERP

2017-06-22 10:39:06

Android開發(fā)者未來

2020-04-21 16:01:13

自動駕駛新基建工信部

2017-10-11 11:17:16

SaaS出路中國式

2020-03-25 09:20:21

自然語言處理

2024-11-21 17:35:10

2012-10-25 16:40:11

WOT高效數(shù)據(jù)中心數(shù)據(jù)中心

2015-01-08 14:52:29

google云計算分布式計算框架

2015-10-13 15:58:38

Javascript循環(huán)變量

2017-09-05 08:30:13

機箱智商產(chǎn)品
點贊
收藏

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