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

還不了解Java的五大BlockingQueue阻塞隊(duì)列源碼,看這篇文章就夠了

開發(fā) 前端
大家用過消息隊(duì)列(MessageQueue),就知道消息隊(duì)列作用是解耦、異步、削峰。同樣BlockingQueue?的作用也是這三種,區(qū)別是BlockingQueue?只作用于本機(jī)器,而消息隊(duì)列相當(dāng)于分布式BlockingQueue。

引言

最近一個(gè)月一直在更新《解讀Java源碼專欄》,其中跟大家一起剖析了Java的常見的5種BlockingQueue(阻塞隊(duì)列),今天就盤點(diǎn)一下這幾種阻塞隊(duì)列的優(yōu)缺點(diǎn)、區(qū)別,以及應(yīng)用場景。

常見的BlockingQueue有以下5種,下面會(huì)詳細(xì)介紹。

  • ArrayBlockingQueue

基于數(shù)組實(shí)現(xiàn)的阻塞隊(duì)列,創(chuàng)建隊(duì)列時(shí)需指定容量大小,是有界隊(duì)列。

  • LinkedBlockingQueue

基于鏈表實(shí)現(xiàn)的阻塞隊(duì)列,默認(rèn)是無界隊(duì)列,創(chuàng)建可以指定容量大小

  • SynchronousQueue

一種沒有緩沖的阻塞隊(duì)列,生產(chǎn)出的數(shù)據(jù)需要立刻被消費(fèi)

  • PriorityBlockingQueue

實(shí)現(xiàn)了優(yōu)先級(jí)的阻塞隊(duì)列,可以按照元素大小排序,是無界隊(duì)列

  • DelayQueue

實(shí)現(xiàn)了延遲功能的阻塞隊(duì)列,基于PriorityQueue實(shí)現(xiàn)的,是無界隊(duì)列

BlockingQueue簡介

這幾種阻塞隊(duì)列都是實(shí)現(xiàn)了BlockingQueue接口,在日常開發(fā)中,我們好像很少用到BlockingQueue(阻塞隊(duì)列),BlockingQueue到底有什么作用?應(yīng)用場景是什么樣的?

如果使用過線程池或者閱讀過線程池源碼,就會(huì)知道線程池的核心功能都是基于BlockingQueue實(shí)現(xiàn)的。

大家用過消息隊(duì)列(MessageQueue),就知道消息隊(duì)列作用是解耦、異步、削峰。同樣BlockingQueue的作用也是這三種,區(qū)別是BlockingQueue只作用于本機(jī)器,而消息隊(duì)列相當(dāng)于分布式BlockingQueue。

圖片

BlockingQueue作為阻塞隊(duì)列,主要應(yīng)用于生產(chǎn)者-消費(fèi)者模式的場景,在并發(fā)多線程中尤其常用。

  1. 比如像線程池中的任務(wù)調(diào)度場景,提交任務(wù)和拉取并執(zhí)行任務(wù)。
  2. 生產(chǎn)者與消費(fèi)者解耦的場景,生產(chǎn)者把數(shù)據(jù)放到隊(duì)列中,消費(fèi)者從隊(duì)列中取數(shù)據(jù)進(jìn)行消費(fèi)。兩者進(jìn)行解耦,不用感知對(duì)方的存在。
  3. 應(yīng)對(duì)突發(fā)流量的場景,業(yè)務(wù)高峰期突然來了很多請(qǐng)求,可以放到隊(duì)列中緩存起來,消費(fèi)者以正常的頻率從隊(duì)列中拉取并消費(fèi)數(shù)據(jù),起到削峰的作用。

BlockingQueue是個(gè)接口,定義了幾組放數(shù)據(jù)和取數(shù)據(jù)的方法,來滿足不同的場景。

操作

拋出異常

返回特定值

阻塞

阻塞一段時(shí)間

放數(shù)據(jù)

add()

offer()

put()

offer(e, time, unit)

取數(shù)據(jù)(同時(shí)刪除數(shù)據(jù))

remove()

poll()

take()

poll(time, unit)

取數(shù)據(jù)(不刪除)

element()

peek()

不支持

不支持

這四組方法的區(qū)別是:

  1. 當(dāng)隊(duì)列滿的時(shí)候,再次添加數(shù)據(jù),add()會(huì)拋出異常,offer()會(huì)返回false,put()會(huì)一直阻塞,offer(e, time, unit)會(huì)阻塞指定時(shí)間,然后返回false。
  2. 當(dāng)隊(duì)列為空的時(shí)候,再次取數(shù)據(jù),remove()會(huì)拋出異常,poll()會(huì)返回null,take()會(huì)一直阻塞,poll(time, unit)會(huì)阻塞指定時(shí)間,然后返回null。

ArrayBlockingQueue

  1. ArrayBlockingQueue底層基于數(shù)組實(shí)現(xiàn),采用循環(huán)數(shù)組,提升了數(shù)組的空間利用率。
  2. ArrayBlockingQueue初始化的時(shí)候,必須指定隊(duì)列長度,是有界的阻塞隊(duì)列,所以要預(yù)估好隊(duì)列長度,保證生產(chǎn)者和消費(fèi)者速率相匹配。
  3. ArrayBlockingQueue的方法是線程安全的,使用ReentrantLock在操作前后加鎖來保證線程安全。

LinkedBlockingQueue

  1. LinkedBlockingQueue底層基于鏈表實(shí)現(xiàn),支持從頭部彈出數(shù)據(jù),從尾部添加數(shù)據(jù)。
  2. LinkedBlockingQueue初始化的時(shí)候,如果不指定隊(duì)列長度,默認(rèn)長度是Integer最大值,相當(dāng)于無界隊(duì)列,有內(nèi)存溢出風(fēng)險(xiǎn),建議初始化的時(shí)候指定隊(duì)列長度。
  3. LinkedBlockingQueue的方法是線程安全的,分別使用了讀寫兩把鎖,比ArrayBlockingQueue性能更好。

與ArrayBlockingQueue區(qū)別是:

  1. 底層結(jié)構(gòu)不同,ArrayBlockingQueue底層基于數(shù)組實(shí)現(xiàn),初始化的時(shí)候必須指定數(shù)組長度,無法擴(kuò)容。LinkedBlockingQueue底層基于鏈表實(shí)現(xiàn),鏈表最大長度是Integer最大值。
  2. 占用內(nèi)存大小不同,ArrayBlockingQueue一旦初始化,數(shù)組長度就確定了,不會(huì)隨著元素增加而改變。LinkedBlockingQueue會(huì)隨著元素越多,鏈表越長,占用內(nèi)存越大。
  3. 性能不同,ArrayBlockingQueue的入隊(duì)和出隊(duì)共用一把鎖,并發(fā)較低。LinkedBlockingQueue入隊(duì)和出隊(duì)使用兩把獨(dú)立的鎖,并發(fā)情況下性能更高。
  4. 公平鎖選項(xiàng),ArrayBlockingQueue初始化的時(shí)候,可以指定使用公平鎖或者非公平鎖,公平鎖模式下,可以按照線程等待的順序來操作隊(duì)列。LinkedBlockingQueue只支持非公平鎖。
  5. 適用場景不同,ArrayBlockingQueue適用于明確限制隊(duì)列大小的場景,防止生產(chǎn)速度大于消費(fèi)速度的時(shí)候,造成內(nèi)存溢出、資源耗盡。LinkedBlockingQueue適用于業(yè)務(wù)高峰期可以自動(dòng)擴(kuò)展消費(fèi)速度的場景。

SynchronousQueue

無論是ArrayBlockingQueue還是LinkedBlockingQueue都是起到緩沖隊(duì)列的作用,當(dāng)消費(fèi)者的消費(fèi)速度跟不上時(shí),任務(wù)就在隊(duì)列中堆積,需要等待消費(fèi)者慢慢消費(fèi)。

如果我們想要自己的任務(wù)快速執(zhí)行,不要積壓在隊(duì)列中,該怎么辦?這時(shí)候就可以使用SynchronousQueue了。

SynchronousQueue被稱為同步隊(duì)列,當(dāng)生產(chǎn)者往隊(duì)列中放元素的時(shí)候,必須等待消費(fèi)者把這個(gè)元素取走,否則一直阻塞。消費(fèi)者取元素的時(shí)候,同理也必須等待生產(chǎn)者放隊(duì)列中放元素。

  1. SynchronousQueue底層有兩種實(shí)現(xiàn)方式,分別是基于棧實(shí)現(xiàn)非公平策略,以及基于隊(duì)列實(shí)現(xiàn)的公平策略。
  2. SynchronousQueue初始化的時(shí)候,可以指定使用公平策略還是非公平策略。
  3. SynchronousQueue不存儲(chǔ)元素,不適合作為緩存隊(duì)列使用。適用于生產(chǎn)者與消費(fèi)者速度相匹配的場景,可減少任務(wù)執(zhí)行的等待時(shí)間。

PriorityBlockingQueue

由于PriorityQueue跟前幾個(gè)阻塞隊(duì)列不一樣,并沒有實(shí)現(xiàn)BlockingQueue接口,只是實(shí)現(xiàn)了Queue接口,所以PriorityQueue并不算阻塞隊(duì)列。Queue接口中定義了幾組放數(shù)據(jù)和取數(shù)據(jù)的方法,來滿足不同的場景。

  1. PriorityQueue實(shí)現(xiàn)了Queue接口,提供了兩組放數(shù)據(jù)和讀數(shù)據(jù)的方法,來滿足不同的場景。
  2. PriorityQueue底層基于數(shù)組實(shí)現(xiàn),實(shí)現(xiàn)了按照元素值大小排序的功能,內(nèi)部按照最小堆存儲(chǔ),實(shí)現(xiàn)了高效的插入和刪除。
  3. PriorityQueue初始化的時(shí)候,可以指定數(shù)組長度和自定義比較器。
  4. PriorityQueue初始容量是11,當(dāng)數(shù)組容量小于64,采用2倍擴(kuò)容,否則采用1.5擴(kuò)容。
  5. PriorityQueue每次都是從數(shù)組頭節(jié)點(diǎn)取元素,取之后需要調(diào)整最小堆。

DelayQueue

DelayQueue是一種本地延遲隊(duì)列,比如希望我們的任務(wù)在5秒后執(zhí)行,就可以使用DelayQueue實(shí)現(xiàn)。常見的使用場景有:

  • 訂單10分鐘內(nèi)未支付,就取消。
  • 緩存過期后,就刪除。
  • 消息的延遲發(fā)送等。
  1. DelayQueue底層采用組合的方式,復(fù)用PriorityQueue的按照延遲時(shí)間排序任務(wù)的功能,實(shí)現(xiàn)了延遲隊(duì)列。
  2. DelayQueue是線程安全的,內(nèi)部使用ReentrantLock加鎖。

總結(jié)

這5種阻塞隊(duì)列的特性各不相同,在使用的時(shí)候該怎么選擇呢?我做了一張圖,供大家參考。

圖片 圖片

責(zé)任編輯:武曉燕 來源: 一燈架構(gòu)
相關(guān)推薦

2021-11-10 07:47:48

Traefik邊緣網(wǎng)關(guān)

2019-09-25 09:17:43

物聯(lián)網(wǎng)技術(shù)信息安全

2017-03-30 22:41:55

虛擬化操作系統(tǒng)軟件

2019-10-30 09:25:58

NginxApache 服務(wù)器

2022-05-27 08:18:00

HashMapHash哈希表

2024-03-26 00:00:06

RedisZSet排行榜

2018-10-31 17:22:25

AI人工智能芯片

2019-10-31 09:48:53

MySQL數(shù)據(jù)庫事務(wù)

2018-08-17 09:14:43

餓了么容器演進(jìn)

2020-10-13 07:44:40

緩存雪崩 穿透

2024-02-28 08:59:47

2022-08-26 05:22:21

RabbitMQ架構(gòu)

2017-12-12 12:53:09

2017-03-10 21:04:04

Android適配

2017-03-07 15:35:26

Android適配 界面

2021-04-09 10:03:12

大數(shù)據(jù)exactly-onc

2021-05-07 07:52:51

Java并發(fā)編程

2019-07-10 15:15:23

JVM虛擬機(jī)Java

2021-09-30 07:59:06

zookeeper一致性算法CAP

2019-08-16 09:41:56

UDP協(xié)議TCP
點(diǎn)贊
收藏

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