日本黄色一级经典视频|伊人久久精品视频|亚洲黄色色周成人视频九九九|av免费网址黄色小短片|黄色Av无码亚洲成年人|亚洲1区2区3区无码|真人黄片免费观看|无码一级小说欧美日免费三级|日韩中文字幕91在线看|精品久久久无码中文字幕边打电话

當前位置:首頁 > 單片機 > 程序員小灰
[導讀]從問題出發(fā),走一遍線程池的思想之旅,你會發(fā)現它很簡單。

小宇:閃客,我最近看到線程池,被里邊亂七八槽的參數給搞暈了,你能不能給我講講呀?

閃客:沒問題,這個我擅長,咱們從一個最簡單的情況開始,假設有一段代碼,你希望異步執(zhí)行它,是不是要寫出這樣的代碼?

new Thread(r).start();
小宇:嗯嗯,最簡單的寫法似乎就是這樣呢。閃客:這種寫法當然可以完成功能,可是你這樣寫,老王這樣寫,老張也這樣寫,程序中到處都是這樣創(chuàng)建線程的方法,能不能寫一個統(tǒng)一的工具類讓大家調用呢?
小宇:可以的,感覺有一個統(tǒng)一的工具類,更優(yōu)雅一些。
閃客:那如果讓你來設計這個工具類,你會怎么寫呢?我先給你定一個接口,你來實現。
public interface Executor {
public void execute(Runnable r);
}
小宇:emmm,我可能先定義幾個成員變量,比如核心線程數、最大線程數 ...反正就是那些亂七八糟的參數。閃客:STOP!小宇呀,你現在深受面試手冊的毒害,你先把這些全部的概念忘掉,就說讓你寫一個最簡單的工具類,第一反應,你會怎么寫?
第一版

小宇:那我可能會這樣

// 新線程:直接創(chuàng)建一個新線程運行
class FlashExecutor implements Executor {
public void execute(Runnable r) {
new Thread(r).start();
}
}
閃客:嗯嗯很好,你的思路非常棒。小宇:啊,我這個會不會太 low 了呀,我還以為你會罵我呢。

怎么會, Doug Lea 大神在 JDK 源碼注釋中給出的就是這樣的例子,這是最根本的功能。你在這個基礎上,嘗試著優(yōu)化一下?

第二版

小宇:還能怎么優(yōu)化呢?這不已經用一個工具類實現了異步執(zhí)行了嘛!

閃客:我問你一個問題,假如有 10000 個人都調用這個工具類提交任務,那就會創(chuàng)建 10000 個線程來執(zhí)行,這肯定不合適吧!能不能控制一下線程的數量呢?
小宇:這不難,我可以把這個任務 r 丟到一個 tasks 隊列中,然后只啟動一個線程,就叫它 Worker 線程吧,不斷從 tasks 隊列中取任務,執(zhí)行任務。這樣無論調用者調用多少次,永遠就只有一個 Worker 線程在運行,像這樣。


閃客:太棒了,這個設計有了三個重大的意義:
1. 控制了線程數量。
2. 隊列不但起到了緩沖的作用,還將任務的提交與執(zhí)行解耦了。
3. 最重要的一點是,解決了每次重復創(chuàng)建和銷毀線程帶來的系統(tǒng)開銷。

小宇:哇真的么,這么小的改動有這么多意義呀。

閃客:那當然,不過只有一個后臺的工作線程 Worker 會不會少了點?還有如果這個 tasks 隊列滿了怎么辦呢?

第三版
小宇:哦,的確,只有一個線程在某些場景下是很吃力的,那我把 Worker 線程的數量增加?

閃客:沒錯,Worker 線程的數量要增加,但是具體數量要讓使用者決定,調用時傳入,就叫核心線程數 corePoolSize 吧。
小宇:好的,那我這樣設計。
1. 初始化線程池時,直接啟動 corePoolSize 個工作線程 Worker 先跑著。
2. 這些 Worker 就是死循環(huán)從隊列里取任務然后執(zhí)行。
3. execute 方法仍然是直接把任務放到隊列,但隊列滿了之后直接拋棄

閃客:太完美了,獎勵你一塊費列羅吧。
小宇:哈哈謝謝,那我先吃一會兒哈。
閃客:好,你邊吃我邊說?,F在我們已經實現了一個至少不那么丑陋的線程池了,但還有幾處小瑕疵,比如初始化的時候,就創(chuàng)建了一堆 Worker 線程在那空跑著,假如此時并沒有異步任務提交過來執(zhí)行,這就有點浪費了。
小宇:哦好像是誒!
閃客:還有,你這隊列一滿,就直接把新任務丟棄了,這樣有些粗暴,能不能讓調用者自己決定該怎么處理呢?
小宇:哎呀,想不到我這么溫柔的妹紙居然寫出了這么粗暴的代碼。
閃客:額,你先把費列羅咽下去吧。
第四版

小宇:我吃完了,現在腦子有點不夠用了,得先消化消化食物,要不你幫我分析分析吧。

閃客:好的,現在我們做出如下改進。

1. 按需創(chuàng)建Worker:剛初始化線程池時,不再立刻創(chuàng)建 corePoolSize 個工作線程,而是等待調用者不斷提交任務的過程中,逐漸把工作線程 Worker 創(chuàng)建出來,等數量達到 corePoolSize 時就停止,把任務直接丟到隊列里。那就必然要用一個屬性記錄已經創(chuàng)建出來的工作線程數量,就叫 workCount 吧。

2. 加拒絕策略:實現上就是增加一個入參,類型是一個接口 RejectedExecutionHandler,由調用者決定實現類,以便在任務提交失敗后執(zhí)行 rejectedExecution 方法。
3. 增加線程工廠:實現上就是增加一個入參,類型是一個接口 ThreadFactory,增加工作線程時不再直接 new 線程,而是調用這個由調用者傳入的 ThreadFactory 實現類的 newThread 方法。
就像下面這樣。

小宇:哇,還是你厲害,這一版應該很完美了吧?閃客:不不不,離完美還差得很遠,接下來的改進,由你來想吧,我這里可以給你一個提示彈性思維

第五版

小宇:彈性思維?哈哈閃客你這術語說的真是越來越不像人話了閃客:咳咳小宇:哦,我是說你肯定是指我這個代碼寫的沒有彈性,對吧?可是彈性是指什么呢?閃客:簡單說,在這個場景里,彈性就是在任務提交比較頻繁,和任務提交非常不頻繁這兩種情況下,你這個代碼是否有問題?小宇:emmm 讓我想想,我這個線程池,當提交任務的量突增時,工作線程和隊列都被占滿了,就只能走拒絕策略,其實就是被丟棄掉閃客:是的小宇:這樣的確是太硬了,誒不過我想了下,調用方可以通過設置很大的核心線程數 corePoolSize 來解決這個問題呀。閃客:的確是可以,但一般場景下 QPS 高峰期都很短,而為了這個很短暫的高峰,設置很大的核心線程數,簡直太浪費資源了,你看上面的圖不覺得眼暈么?小宇:是呀,那怎么辦呢,太大了也不行,太小了也不行。閃客:我們可以發(fā)明一個新的屬性,叫最大線程數 maximumPoolSize。當核心線程數和隊列都滿了時,新提交的任務仍然可以通過創(chuàng)建新的工作線程(叫它非核心線程),直到工作線程數達到 maximumPoolSize 為止,這樣就可以緩解一時的高峰期了,而用戶也不用設置過大的核心線程數。

小宇:哦好像有點感覺了,可是具體怎么操作呢?閃客:想象力不行呀小宇,那你看下面的演示。
1. 開始的時候和上一版一樣,當 workCount < corePoolSize 時,通過創(chuàng)建新的 Worker 來執(zhí)行任務。
2. 當 workCount >= corePoolSize 就停止創(chuàng)建新線程,把任務直接丟到隊列里。
3. 但當隊列已滿且仍然 workCount < maximumPoolSize 時,不再直接走拒絕策略,而是創(chuàng)建非核心線程,直到 workCount = maximumPoolSize,再走拒絕策略。
小宇:哎呀,我怎么沒想到,這樣 corePoolSize 就負責平時大多數情況所需要的工作線程數,而 maximumPoolSize 就負責在高峰期臨時擴充工作線程數。閃客:沒錯,高峰時期的彈性搞定了,那自然就還要考慮低谷時期。當長時間沒有任務提交時,核心線程與非核心線程都一直空跑著,浪費資源。我們可以給非核心線程設定一個超時時間 keepAliveTime,當這么長時間沒能從隊列里獲取任務時,就不再等了,銷毀線程。


小宇:嗯,這回咱們的線程池在 QPS 高峰時可以臨時擴容,QPS 低谷時又可以及時回收線程(非核心線程)而不至于浪費資源,真的顯得十分 Q 彈呢。閃客:是呀是呀。誒不對,怎么又變成我說了,不是說這一版你來思考么?小宇:我也想啊,但你這一講技術就自說自話的毛病老是不改,我有啥辦法。閃客:額抱歉抱歉,那接下來你總結一下我們的線程池吧

總結

小宇:嗯好的,首先它的構造方法是這個樣子滴public FlashExecutor(
int corePoolSize,
int maximumPoolSize,
long keepAliveTime,
TimeUnit unit,
BlockingQueueworkQueue,
ThreadFactory threadFactory,
RejectedExecutionHandler handler)

{
... // 省略一些參數校驗
this.corePoolSize = corePoolSize;
this.maximumPoolSize = maximumPoolSize;
this.workQueue = workQueue;
this.keepAliveTime = unit.toNanos(keepAliveTime);
this.threadFactory = threadFactory;
this.handler = handler;
}

這些參數分別是
int corePoolSize:核心線程數int maximumPoolSize:最大線程數long keepAliveTime:非核心線程的空閑時間TimeUnit unit:空閑時間的單位BlockingQueueworkQueue:任務隊列(線程安全的阻塞隊列)ThreadFactory threadFactory:線程工廠RejectedExecutionHandler handler:拒絕策略整個任務的提交流程是閃客:不錯不錯,這可是你自己總結的喲,現在還用我給你講什么是線程池了么?小宇:啊天呢,我才發(fā)現這似乎就是我一直弄不清楚的線程池的參數和原理呢!閃客:沒錯,而且最后一版代碼的構造方法,就是 Java 面試??嫉?ThreadPoolExecutor 最長的那個構造方法,參數名都沒變。小宇:哇,太贊了!我都忘了一開始我想干嘛了,嘻嘻。閃客:哈哈,不知不覺學到了技術才爽呢,對吧?晚飯時間快到了,要不要一塊去吃山西面館呀?小宇:哦,那家店餐桌的顏色我不太喜歡,下次吧。閃客:哦好吧。

后記
線程池是面試常考的知識點,網上很多文章都是直接從它那有 7 個參數的構造方法講起,強行把各個參數的含義說給你聽,讓人云里霧里。希望讀者讀完本篇文章后,線程池的這些參數不再是死記硬背,而是像本文中這些動圖一樣在你的腦中活靈活現,這樣就能永遠記住他們啦~

本站聲明: 本文章由作者或相關機構授權發(fā)布,目的在于傳遞更多信息,并不代表本站贊同其觀點,本站亦不保證或承諾內容真實性等。需要轉載請聯(lián)系該專欄作者,如若文章內容侵犯您的權益,請及時聯(lián)系本站刪除。
換一批
延伸閱讀

LED驅動電源的輸入包括高壓工頻交流(即市電)、低壓直流、高壓直流、低壓高頻交流(如電子變壓器的輸出)等。

關鍵字: 驅動電源

在工業(yè)自動化蓬勃發(fā)展的當下,工業(yè)電機作為核心動力設備,其驅動電源的性能直接關系到整個系統(tǒng)的穩(wěn)定性和可靠性。其中,反電動勢抑制與過流保護是驅動電源設計中至關重要的兩個環(huán)節(jié),集成化方案的設計成為提升電機驅動性能的關鍵。

關鍵字: 工業(yè)電機 驅動電源

LED 驅動電源作為 LED 照明系統(tǒng)的 “心臟”,其穩(wěn)定性直接決定了整個照明設備的使用壽命。然而,在實際應用中,LED 驅動電源易損壞的問題卻十分常見,不僅增加了維護成本,還影響了用戶體驗。要解決這一問題,需從設計、生...

關鍵字: 驅動電源 照明系統(tǒng) 散熱

根據LED驅動電源的公式,電感內電流波動大小和電感值成反比,輸出紋波和輸出電容值成反比。所以加大電感值和輸出電容值可以減小紋波。

關鍵字: LED 設計 驅動電源

電動汽車(EV)作為新能源汽車的重要代表,正逐漸成為全球汽車產業(yè)的重要發(fā)展方向。電動汽車的核心技術之一是電機驅動控制系統(tǒng),而絕緣柵雙極型晶體管(IGBT)作為電機驅動系統(tǒng)中的關鍵元件,其性能直接影響到電動汽車的動力性能和...

關鍵字: 電動汽車 新能源 驅動電源

在現代城市建設中,街道及停車場照明作為基礎設施的重要組成部分,其質量和效率直接關系到城市的公共安全、居民生活質量和能源利用效率。隨著科技的進步,高亮度白光發(fā)光二極管(LED)因其獨特的優(yōu)勢逐漸取代傳統(tǒng)光源,成為大功率區(qū)域...

關鍵字: 發(fā)光二極管 驅動電源 LED

LED通用照明設計工程師會遇到許多挑戰(zhàn),如功率密度、功率因數校正(PFC)、空間受限和可靠性等。

關鍵字: LED 驅動電源 功率因數校正

在LED照明技術日益普及的今天,LED驅動電源的電磁干擾(EMI)問題成為了一個不可忽視的挑戰(zhàn)。電磁干擾不僅會影響LED燈具的正常工作,還可能對周圍電子設備造成不利影響,甚至引發(fā)系統(tǒng)故障。因此,采取有效的硬件措施來解決L...

關鍵字: LED照明技術 電磁干擾 驅動電源

開關電源具有效率高的特性,而且開關電源的變壓器體積比串聯(lián)穩(wěn)壓型電源的要小得多,電源電路比較整潔,整機重量也有所下降,所以,現在的LED驅動電源

關鍵字: LED 驅動電源 開關電源

LED驅動電源是把電源供應轉換為特定的電壓電流以驅動LED發(fā)光的電壓轉換器,通常情況下:LED驅動電源的輸入包括高壓工頻交流(即市電)、低壓直流、高壓直流、低壓高頻交流(如電子變壓器的輸出)等。

關鍵字: LED 隧道燈 驅動電源
關閉