您好,登錄后才能下訂單哦!
本篇文章給大家分享的是有關(guān)Disruptor中鎖對(duì)性能有什么影響,小編覺得挺實(shí)用的,因此分享給大家學(xué)習(xí),希望大家閱讀完這篇文章后可以有所收獲,話不多說,跟著小編一起來看看吧。
Disruptor是英國外匯交易公司LMAX開發(fā)的一個(gè)高性能隊(duì)列,研發(fā)的初衷是解決內(nèi)存隊(duì)列的延遲問題(在性能測(cè)試中發(fā)現(xiàn)竟然與I/O操作處于同樣的數(shù)量級(jí))?;贒isruptor開發(fā)的系統(tǒng)單線程能支撐每秒600萬訂單,2010年在QCon演講后,獲得了業(yè)界關(guān)注。2011年,企業(yè)應(yīng)用軟件專家Martin Fowler專門撰寫長(zhǎng)文介紹。同年它還獲得了Oracle官方的Duke大獎(jiǎng)。
目前,包括Apache Storm、Camel、Log4j 2在內(nèi)的很多知名項(xiàng)目都應(yīng)用了Disruptor以獲取高性能。在美團(tuán)技術(shù)團(tuán)隊(duì)它也有不少應(yīng)用,有的項(xiàng)目架構(gòu)借鑒了它的設(shè)計(jì)機(jī)制。本文從實(shí)戰(zhàn)角度剖析了Disruptor的實(shí)現(xiàn)原理。
需要特別指出的是,這里所說的隊(duì)列是系統(tǒng)內(nèi)部的內(nèi)存隊(duì)列,而不是Kafka這樣的分布式隊(duì)列。另外,本文所描述的Disruptor特性限于3.3.4。
介紹Disruptor之前,我們先來看一看常用的線程安全的內(nèi)置隊(duì)列有什么問題。Java的內(nèi)置隊(duì)列如下表所示。
隊(duì)列 | 有界性 | 鎖 | 數(shù)據(jù)結(jié)構(gòu) |
---|---|---|---|
ArrayBlockingQueue | bounded | 加鎖 | arraylist |
LinkedBlockingQueue | optionally-bounded | 加鎖 | linkedlist |
ConcurrentLinkedQueue | unbounded | 無鎖 | linkedlist |
LinkedTransferQueue | unbounded | 無鎖 | linkedlist |
PriorityBlockingQueue | unbounded | 加鎖 | heap |
DelayQueue | unbounded | 加鎖 | heap |
隊(duì)列的底層一般分成三種:數(shù)組、鏈表和堆。其中,堆一般情況下是為了實(shí)現(xiàn)帶有優(yōu)先級(jí)特性的隊(duì)列,暫且不考慮。
我們就從數(shù)組和鏈表兩種數(shù)據(jù)結(jié)構(gòu)來看,基于數(shù)組線程安全的隊(duì)列,比較典型的是ArrayBlockingQueue,它主要通過加鎖的方式來保證線程安全;基于鏈表的線程安全隊(duì)列分成LinkedBlockingQueue和ConcurrentLinkedQueue兩大類,前者也通過鎖的方式來實(shí)現(xiàn)線程安全,而后者以及上面表格中的LinkedTransferQueue都是通過原子變量compare and swap(以下簡(jiǎn)稱“CAS”)這種不加鎖的方式來實(shí)現(xiàn)的。
通過不加鎖的方式實(shí)現(xiàn)的隊(duì)列都是無界的(無法保證隊(duì)列的長(zhǎng)度在確定的范圍內(nèi));而加鎖的方式,可以實(shí)現(xiàn)有界隊(duì)列。在穩(wěn)定性要求特別高的系統(tǒng)中,為了防止生產(chǎn)者速度過快,導(dǎo)致內(nèi)存溢出,只能選擇有界隊(duì)列;同時(shí),為了減少Java的垃圾回收對(duì)系統(tǒng)性能的影響,會(huì)盡量選擇array/heap格式的數(shù)據(jù)結(jié)構(gòu)。這樣篩選下來,符合條件的隊(duì)列就只有ArrayBlockingQueue。
ArrayBlockingQueue在實(shí)際使用過程中,會(huì)因?yàn)榧渔i和偽共享等出現(xiàn)嚴(yán)重的性能問題,我們下面來分析一下。
現(xiàn)實(shí)編程過程中,加鎖通常會(huì)嚴(yán)重地影響性能。線程會(huì)因?yàn)楦?jìng)爭(zhēng)不到鎖而被掛起,等鎖被釋放的時(shí)候,線程又會(huì)被恢復(fù),這個(gè)過程中存在著很大的開銷,并且通常會(huì)有較長(zhǎng)時(shí)間的中斷,因?yàn)楫?dāng)一個(gè)線程正在等待鎖時(shí),它不能做任何其他事情。如果一個(gè)線程在持有鎖的情況下被延遲執(zhí)行,例如發(fā)生了缺頁錯(cuò)誤、調(diào)度延遲或者其它類似情況,那么所有需要這個(gè)鎖的線程都無法執(zhí)行下去。如果被阻塞線程的優(yōu)先級(jí)較高,而持有鎖的線程優(yōu)先級(jí)較低,就會(huì)發(fā)生優(yōu)先級(jí)反轉(zhuǎn)。
Disruptor論文中講述了一個(gè)實(shí)驗(yàn):
這個(gè)測(cè)試程序調(diào)用了一個(gè)函數(shù),該函數(shù)會(huì)對(duì)一個(gè)64位的計(jì)數(shù)器循環(huán)自增5億次。
機(jī)器環(huán)境:2.4G 6核
運(yùn)算: 64位的計(jì)數(shù)器累加5億次
Method | Time (ms) |
---|---|
Single thread | 300 |
Single thread with CAS | 5,700 |
Single thread with lock | 10,000 |
Single thread with volatile write | 4,700 |
Two threads with CAS | 30,000 |
Two threads with lock | 224,000 |
CAS操作比單線程無鎖慢了1個(gè)數(shù)量級(jí);有鎖且多線程并發(fā)的情況下,速度比單線程無鎖慢3個(gè)數(shù)量級(jí)??梢姛o鎖速度最快。
單線程情況下,不加鎖的性能 > CAS操作的性能 > 加鎖的性能。
在多線程情況下,為了保證線程安全,必須使用CAS或鎖,這種情況下,CAS的性能超過鎖的性能,前者大約是后者的8倍。
以上就是Disruptor中鎖對(duì)性能有什么影響,小編相信有部分知識(shí)點(diǎn)可能是我們?nèi)粘9ぷ鲿?huì)見到或用到的。希望你能通過這篇文章學(xué)到更多知識(shí)。更多詳情敬請(qǐng)關(guān)注億速云行業(yè)資訊頻道。
免責(zé)聲明:本站發(fā)布的內(nèi)容(圖片、視頻和文字)以原創(chuàng)、轉(zhuǎn)載和分享為主,文章觀點(diǎn)不代表本網(wǎng)站立場(chǎng),如果涉及侵權(quán)請(qǐng)聯(lián)系站長(zhǎng)郵箱:is@yisu.com進(jìn)行舉報(bào),并提供相關(guān)證據(jù),一經(jīng)查實(shí),將立刻刪除涉嫌侵權(quán)內(nèi)容。