成人免费xxxxx在线视频软件_久久精品久久久_亚洲国产精品久久久_天天色天天色_亚洲人成一区_欧美一级欧美三级在线观看

圖解 | 你管這玩意叫線程池?

網(wǎng)絡(luò) 通信技術(shù)
實現(xiàn)上就是增加一個入?yún)ⅲ愋褪且粋€接口 ThreadFactory,增加工作線程時不再直接 new 線程,而是調(diào)用這個由調(diào)用者傳入的 ThreadFactory 實現(xiàn)類的 newThread 方法。

 [[375802]]

本文轉(zhuǎn)載自微信公眾號「低并發(fā)編程」,作者閃客sun 。轉(zhuǎn)載本文請聯(lián)系低并發(fā)編程公眾號。  

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

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

  1. new Thread(r).start(); 

小宇:嗯嗯,最簡單的寫法似乎就是這樣呢。

閃客:這種寫法當(dāng)然可以完成功能,可是你這樣寫,老王這樣寫,老張也這樣寫,程序中到處都是這樣創(chuàng)建線程的方法,能不能寫一個統(tǒng)一的工具類讓大家調(diào)用呢?

小宇:可以的,感覺有一個統(tǒng)一的工具類,更優(yōu)雅一些。

閃客:那如果讓你來設(shè)計這個工具類,你會怎么寫呢?我先給你定一個接口,你來實現(xiàn)。

  1. public interface Executor { 
  2.     public void execute(Runnable r); 

小宇:emmm,我可能先定義幾個成員變量,比如核心線程數(shù)、最大線程數(shù) ...反正就是那些亂七八糟的參數(shù)。

閃客:STOP!小宇呀,你現(xiàn)在深受面試手冊的毒害,你先把這些全部的概念忘掉,就說讓你寫一個最簡單的工具類,第一反應(yīng),你會怎么寫?

第一版

小宇:那我可能會這樣

  1. // 新線程:直接創(chuàng)建一個新線程運行 
  2. class FlashExecutor implements Executor { 
  3.     public void execute(Runnable r) { 
  4.         new Thread(r).start(); 
  5.     } 

閃客:嗯嗯很好,你的思路非常棒。

小宇:啊,我這個會不會太 low 了呀,我還以為你會罵我呢。

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

第二版

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

閃客:我問你一個問題,假如有 10000 個人都調(diào)用這個工具類提交任務(wù),那就會創(chuàng)建 10000 個線程來執(zhí)行,這肯定不合適吧!能不能控制一下線程的數(shù)量呢?

小宇:這不難,我可以把這個任務(wù) r 丟到一個 tasks 隊列中,然后只啟動一個線程,就叫它 Worker 線程吧,不斷從 tasks 隊列中取任務(wù),執(zhí)行任務(wù)。這樣無論調(diào)用者調(diào)用多少次,永遠就只有一個 Worker 線程在運行,像這樣。

閃客:太棒了,這個設(shè)計有了三個重大的意義:

1. 控制了線程數(shù)量。

2. 隊列不但起到了緩沖的作用,還將任務(wù)的提交與執(zhí)行解耦了。

3. 最重要的一點是,解決了每次重復(fù)創(chuàng)建和銷毀線程帶來的系統(tǒng)開銷。

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

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

第三版

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

閃客:沒錯,Worker 線程的數(shù)量要增加,但是具體數(shù)量要讓使用者決定,調(diào)用時傳入,就叫核心線程數(shù) corePoolSize 吧。

小宇:好的,那我這樣設(shè)計。

1. 初始化線程池時,直接啟動 corePoolSize 個工作線程 Worker 先跑著。

2. 這些 Worker 就是死循環(huán)從隊列里取任務(wù)然后執(zhí)行。

3. execute 方法仍然是直接把任務(wù)放到隊列,但隊列滿了之后直接拋棄

閃客:太完美了,獎勵你一塊費列羅吧。

小宇:哈哈謝謝,那我先吃一會兒哈。

閃客:好,你邊吃我邊說。現(xiàn)在我們已經(jīng)實現(xiàn)了一個至少不那么丑陋的線程池了,但還有幾處小瑕疵,比如初始化的時候,就創(chuàng)建了一堆 Worker 線程在那空跑著,假如此時并沒有異步任務(wù)提交過來執(zhí)行,這就有點浪費了。

小宇:哦好像是誒!

閃客:還有,你這隊列一滿,就直接把新任務(wù)丟棄了,這樣有些粗暴,能不能讓調(diào)用者自己決定該怎么處理呢?

小宇:哎呀,想不到我這么溫柔的妹紙居然寫出了這么粗暴的代碼。

閃客:額,你先把費列羅咽下去吧。

第四版

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

閃客:好的,現(xiàn)在我們做出如下改進。

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

2. 加拒絕策略:實現(xiàn)上就是增加一個入?yún)ⅲ愋褪且粋€接口 RejectedExecutionHandler,由調(diào)用者決定實現(xiàn)類,以便在任務(wù)提交失敗后執(zhí)行 rejectedExecution 方法。

3. 增加線程工廠:實現(xiàn)上就是增加一個入?yún)ⅲ愋褪且粋€接口 ThreadFactory,增加工作線程時不再直接 new 線程,而是調(diào)用這個由調(diào)用者傳入的 ThreadFactory 實現(xiàn)類的 newThread 方法。

就像下面這樣。

小宇:哇,還是你厲害,這一版應(yīng)該很完美了吧?

閃客:不不不,離完美還差得很遠,接下來的改進,由你來想吧,我這里可以給你一個提示

彈性思維

第五版

小宇:彈性思維?哈哈閃客你這術(shù)語說的真是越來越不像人話了

閃客:咳咳

小宇:哦,我是說你肯定是指我這個代碼寫的沒有彈性,對吧?可是彈性是指什么呢?

閃客:簡單說,在這個場景里,彈性就是在任務(wù)提交比較頻繁,和任務(wù)提交非常不頻繁這兩種情況下,你這個代碼是否有問題?

小宇:emmm 讓我想想,我這個線程池,當(dāng)提交任務(wù)的量突增時,工作線程和隊列都被占滿了,就只能走拒絕策略,其實就是被丟棄掉

閃客:是的

小宇:這樣的確是太硬了,誒不過我想了下,調(diào)用方可以通過設(shè)置很大的核心線程數(shù) corePoolSize 來解決這個問題呀。

閃客:的確是可以,但一般場景下 QPS 高峰期都很短,而為了這個很短暫的高峰,設(shè)置很大的核心線程數(shù),簡直太浪費資源了,你看上面的圖不覺得眼暈么?

小宇:是呀,那怎么辦呢,太大了也不行,太小了也不行。

閃客:我們可以發(fā)明一個新的屬性,叫最大線程數(shù) maximumPoolSize。當(dāng)核心線程數(shù)和隊列都滿了時,新提交的任務(wù)仍然可以通過創(chuàng)建新的工作線程(叫它非核心線程),直到工作線程數(shù)達到 maximumPoolSize 為止,這樣就可以緩解一時的高峰期了,而用戶也不用設(shè)置過大的核心線程數(shù)。

小宇:哦好像有點感覺了,可是具體怎么操作呢?

閃客:想象力不行呀小宇,那你看下面的演示。

1. 開始的時候和上一版一樣,當(dāng) workCount < corePoolSize 時,通過創(chuàng)建新的 Worker 來執(zhí)行任務(wù)。

2. 當(dāng) workCount >= corePoolSize 就停止創(chuàng)建新線程,把任務(wù)直接丟到隊列里。

3. 但當(dāng)隊列已滿且仍然 workCount < maximumPoolSize 時,不再直接走拒絕策略,而是創(chuàng)建非核心線程,直到 workCount = maximumPoolSize,再走拒絕策略。

小宇:哎呀,我怎么沒想到,這樣 corePoolSize 就負責(zé)平時大多數(shù)情況所需要的工作線程數(shù),而 maximumPoolSize 就負責(zé)在高峰期臨時擴充工作線程數(shù)。

閃客:沒錯,高峰時期的彈性搞定了,那自然就還要考慮低谷時期。當(dāng)長時間沒有任務(wù)提交時,核心線程與非核心線程都一直空跑著,浪費資源。我們可以給非核心線程設(shè)定一個超時時間 keepAliveTime,當(dāng)這么長時間沒能從隊列里獲取任務(wù)時,就不再等了,銷毀線程。

小宇:嗯,這回咱們的線程池在 QPS 高峰時可以臨時擴容,QPS 低谷時又可以及時回收線程(非核心線程)而不至于浪費資源,真的顯得十分 Q 彈呢。

閃客:是呀是呀。誒不對,怎么又變成我說了,不是說這一版你來思考么?

小宇:我也想啊,但你這一講技術(shù)就自說自話的毛病老是不改,我有啥辦法。

閃客:額抱歉抱歉,那接下來你總結(jié)一下我們的線程池吧

總結(jié)

小宇:嗯好的,首先它的構(gòu)造方法是這個樣子滴

  1. public FlashExecutor( 
  2.         int corePoolSize, 
  3.         int maximumPoolSize, 
  4.         long keepAliveTime, 
  5.         TimeUnit unit, 
  6.         BlockingQueue<Runnable> workQueue, 
  7.         ThreadFactory threadFactory, 
  8.         RejectedExecutionHandler handler)  
  9.     ... // 省略一些參數(shù)校驗 
  10.     this.corePoolSize = corePoolSize; 
  11.     this.maximumPoolSize = maximumPoolSize; 
  12.     this.workQueue = workQueue; 
  13.     this.keepAliveTime = unit.toNanos(keepAliveTime); 
  14.     this.threadFactory = threadFactory; 
  15.     this.handler = handler; 

這些參數(shù)分別是

int corePoolSize:核心線程數(shù)

int maximumPoolSize:最大線程數(shù)

long keepAliveTime:非核心線程的空閑時間

TimeUnit unit:空閑時間的單位

BlockingQueue workQueue:任務(wù)隊列(線程安全的阻塞隊列)

ThreadFactory threadFactory:線程工廠

RejectedExecutionHandler handler:拒絕策略

整個任務(wù)的提交流程是

閃客:不錯不錯,這可是你自己總結(jié)的喲,現(xiàn)在還用我給你講什么是線程池了么?

小宇:啊天呢,我才發(fā)現(xiàn)這似乎就是我一直弄不清楚的線程池的參數(shù)和原理呢!

閃客:沒錯,而且最后一版代碼的構(gòu)造方法,就是 Java 面試常考的 ThreadPoolExecutor 最長的那個構(gòu)造方法,參數(shù)名都沒變。

小宇:哇,太贊了!我都忘了一開始我想干嘛了,嘻嘻。

閃客:哈哈,不知不覺學(xué)到了技術(shù)才爽呢,對吧?晚飯時間快到了,要不要一塊去吃山西面館呀?

小宇:哦,那家店餐桌的顏色我不太喜歡,下次吧。

閃客:哦好吧。

后記

線程池是面試常考的知識點,網(wǎng)上很多文章都是直接從它那有 7 個參數(shù)的構(gòu)造方法講起,強行把各個參數(shù)的含義說給你聽,讓人云里霧里。

希望讀者讀完本篇文章后,線程池的這些參數(shù)不再是死記硬背,而是像本文中這些動圖一樣在你的腦中活靈活現(xiàn),這樣就能永遠記住他們啦~

 

責(zé)任編輯:武曉燕 來源: 低并發(fā)編程
相關(guān)推薦

2021-03-04 13:14:54

文件系統(tǒng)存儲

2021-02-04 11:01:59

計算機信號轉(zhuǎn)換

2021-03-11 12:27:36

java 變量數(shù)量

2021-04-26 08:16:18

CPU 語言編寫

2024-05-29 08:56:31

2021-05-17 18:27:20

Token驗證HTTP

2022-05-10 09:16:50

MQ內(nèi)存消費者

2022-02-07 09:40:10

高可用高并發(fā)高性能

2021-07-14 18:21:50

負載均衡TCP網(wǎng)關(guān)

2023-05-15 10:03:00

Redis緩存穿透

2025-01-21 14:11:32

2022-10-09 09:38:10

高可用設(shè)計

2022-03-14 17:56:15

云廠商系統(tǒng)阿里云

2022-02-10 08:07:45

DubboRPC框架

2021-04-29 20:10:17

安全線程存儲

2022-12-15 22:01:04

TLog日志標(biāo)簽

2020-02-07 10:06:34

高管面試管理者

2023-06-08 07:48:03

Java線程池

2024-04-02 09:45:27

線程池Executors開發(fā)

2021-08-11 22:17:48

負載均衡LVS機制
點贊
收藏

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

主站蜘蛛池模板: 亚洲欧美综合 | 亚洲视频一区二区三区四区 | 欧美久久久久久久 | 午夜精品久久久久久久久久久久 | 亚洲欧美一区二区三区在线 | 国产精品不卡一区二区三区 | 国产一区二区精 | 成人毛片一区二区三区 | 男女免费在线观看视频 | 黑人巨大精品欧美黑白配亚洲 | av中文字幕在线播放 | 亚洲精品乱码久久久久久按摩 | 国产视频二区 | 久久久久久久一区 | 国产精品久久 | 日韩中文字幕一区二区三区 | www.狠狠干 | 国产精品久久久久久吹潮日韩动画 | 亚洲视频精品在线 | 在线视频成人 | 亚洲午夜av久久乱码 | 国产精品久久久久久久粉嫩 | 中文字幕乱码一区二区三区 | 在线看91 | 涩涩操 | 欧美一区二区免费 | 久久精品国产一区二区三区 | 99tv| 青青草视频免费观看 | 99精品欧美一区二区蜜桃免费 | 国产精品有限公司 | 亚洲综合区| 亚洲精品久 | 国产精品一区二区在线播放 | 亚洲有码转帖 | 日韩精品视频一区二区三区 | 欧美成年黄网站色视频 | 午夜在线电影网 | 免费一级欧美在线观看视频 | 精品乱码一区二区三四区视频 | 精品视频一区二区三区 |