非阻塞同步算法與CAS(Compare和Swap)無鎖算法

鎖(lock)的代價

鎖是用來做并發(fā)最簡單的方式彼水,當然其代價也是最高的。內(nèi)核態(tài)的鎖的時候需要操作系統(tǒng)進行一次上下文切換,加鎖掀亥、釋放鎖會導致比較多的上下文切換和調(diào)度延時,等待鎖的線程會被掛起直至鎖釋放妥色。在上下文切換的時候搪花,cpu之前緩存的指令和數(shù)據(jù)都將失效,對性能有很大的損失嘹害。操作系統(tǒng)對多線程的鎖進行判斷就像兩姐妹在為一個玩具在爭吵撮竿,然后操作系統(tǒng)就是能決定他們誰能拿到玩具的父母,這是很慢的笔呀。用戶態(tài)的鎖雖然避免了這些問題幢踏,但是其實它們只是在沒有真實的競爭時才有效。

Java在JDK1.5之前都是靠synchronized關(guān)鍵字保證同步的许师,這種通過使用一致的鎖定協(xié)議來協(xié)調(diào)對共享狀態(tài)的訪問房蝉,可以確保無論哪個線程持有守護變量的鎖,都采用獨占的方式來訪問這些變量微渠,如果出現(xiàn)多個線程同時訪問鎖搭幻,那第一些線線程將被掛起,當線程恢復執(zhí)行時逞盆,必須等待其它線程執(zhí)行完他們的時間片以后才能被調(diào)度執(zhí)行檀蹋,在掛起和恢復執(zhí)行過程中存在著很大的開銷。鎖還存在著其它一些缺點纳击,當一個線程正在等待鎖時续扔,它不能做任何事。如果一個線程在持有鎖的情況下被延遲執(zhí)行焕数,那么所有需要這個鎖的線程都無法執(zhí)行下去纱昧。如果被阻塞的線程優(yōu)先級高,而持有鎖的線程優(yōu)先級低堡赔,將會導致優(yōu)先級反轉(zhuǎn)(Priority Inversion)识脆。

樂觀鎖與悲觀鎖

獨占鎖是一種悲觀鎖,synchronized就是一種獨占鎖,它假設(shè)最壞的情況灼捂,并且只有在確保其它線程不會造成干擾的情況下執(zhí)行离例,會導致其它所有需要鎖的線程掛起,等待持有鎖的線程釋放鎖悉稠。而另一個更加有效的鎖就是樂觀鎖宫蛆。所謂樂觀鎖就是,每次不加鎖而是假設(shè)沒有沖突而去完成某項操作的猛,如果因為沖突失敗就重試耀盗,直到成功為止。

volatile的問題

與鎖相比卦尊,volatile變量是一個更輕量級的同步機制叛拷,因為在使用這些變量時不會發(fā)生上下文切換和線程調(diào)度等操作,但是volatile變量也存在一些局限:不能用于構(gòu)建原子的復合操作岂却,因此當一個變量依賴舊值時就不能使用volatile變量忿薇。

Java中的原子操作( atomic operations)

原子操作指的是在一步之內(nèi)就完成而且不能被中斷。原子操作在多線程環(huán)境中是線程安全的躏哩,無需考慮同步的問題署浩。在java中,下列操作是原子操作:

all assignments of primitive types except for long and double

all assignments of references

all operations of java.concurrent.Atomic* classes

all assignments to volatile longs and doubles

問題來了震庭,為什么long型賦值不是原子操作呢瑰抵?例如:

long?foo = 65465498L;

實時上java會分兩步寫入這個long變量,先寫32位器联,再寫后32位二汛。這樣就線程不安全了。如果改成下面的就線程安全了:

private?volatile?long?foo;

因為volatile內(nèi)部已經(jīng)做了synchronized.

CAS無鎖算法

要實現(xiàn)無鎖(lock-free)的非阻塞算法有多種實現(xiàn)方法拨拓,其中CAS(比較與交換肴颊,Compare and swap)是一種有名的無鎖算法。CAS, CPU指令渣磷,在大多數(shù)處理器架構(gòu)婿着,包括IA32、Space中采用的都是CAS指令醋界,CAS的語義是“我認為V的值應(yīng)該為A竟宋,如果是,那么將V的值更新為B形纺,否則不修改并告訴V的值實際為多少”丘侠,CAS是項樂觀鎖技術(shù),當多個線程嘗試使用CAS同時更新同一個變量時逐样,只有其中一個線程能更新變量的值蜗字,而其它線程都失敗肋坚,失敗的線程并不會被掛起蕴忆,而是被告知這次競爭中失敗,并可以再次嘗試击胜。CAS有3個操作數(shù)葵第,內(nèi)存值V苇倡,舊的預期值A(chǔ)邮弹,要修改的新值B泰鸡。當且僅當預期值A(chǔ)和內(nèi)存值V相同時,將內(nèi)存值V修改為B妄讯,否則什么都不做孩锡。CAS無鎖算法的C實現(xiàn)如下:

int?compare_and_swap (int* reg, int?oldval, int?newval)

{

??ATOMIC();

??int?old_reg_val = *reg;

??if?(old_reg_val == oldval)

?????*reg = newval;

??END_ATOMIC();

??return?old_reg_val;

}

CAS(樂觀鎖算法)的基本假設(shè)前提

CAS比較與交換的偽代碼可以表示為:

do{

備份舊數(shù)據(jù);

基于舊數(shù)據(jù)構(gòu)造新數(shù)據(jù)亥贸;

}while(!CAS( 內(nèi)存地址,備份的舊數(shù)據(jù)浇垦,新數(shù)據(jù) ))

(上圖的解釋:CPU去更新一個值炕置,但如果想改的值不再是原來的值,操作就失敗男韧,因為很明顯朴摊,有其它操作先改變了這個值。)

就是指當兩者進行比較時此虑,如果相等甚纲,則證明共享數(shù)據(jù)沒有被修改,替換成新值朦前,然后繼續(xù)往下運行介杆;如果不相等,說明共享數(shù)據(jù)已經(jīng)被修改韭寸,放棄已經(jīng)所做的操作春哨,然后重新執(zhí)行剛才的操作。容易看出 CAS 操作是基于共享數(shù)據(jù)不會被修改的假設(shè)恩伺,采用了類似于數(shù)據(jù)庫的 commit-retry 的模式赴背。當同步?jīng)_突出現(xiàn)的機會很少時,這種假設(shè)能帶來較大的性能提升晶渠。

CAS的開銷(CPU Cache Miss problem)

前面說過了凰荚,CAS(比較并交換)是CPU指令級的操作,只有一步原子操作褒脯,所以非潮闵快。而且CAS避免了請求操作系統(tǒng)來裁定鎖的問題憨颠,不用麻煩操作系統(tǒng)胳徽,直接在CPU內(nèi)部就搞定了积锅。但CAS就沒有開銷了嗎?不养盗!有cache miss的情況缚陷。這個問題比較復雜,首先需要了解CPU的硬件體系結(jié)構(gòu):

上圖可以看到一個8核CPU計算機系統(tǒng)往核,每個CPU有cache(CPU內(nèi)部的高速緩存箫爷,寄存器),管芯內(nèi)還帶有一個互聯(lián)模塊聂儒,使管芯內(nèi)的兩個核可以互相通信虎锚。在圖中央的系統(tǒng)互聯(lián)模塊可以讓四個管芯相互通信,并且將管芯與主存連接起來衩婚。數(shù)據(jù)以“緩存線”為單位在系統(tǒng)中傳輸窜护,“緩存線”對應(yīng)于內(nèi)存中一個 2 的冪大小的字節(jié)塊,大小通常為 32 到 256 字節(jié)之間非春。當 CPU 從內(nèi)存中讀取一個變量到它的寄存器中時柱徙,必須首先將包含了該變量的緩存線讀取到 CPU 高速緩存。同樣地奇昙,CPU 將寄存器中的一個值存儲到內(nèi)存時护侮,不僅必須將包含了該值的緩存線讀到 CPU 高速緩存,還必須確保沒有其他 CPU 擁有該緩存線的拷貝储耐。

比如羊初,如果 CPU0 在對一個變量執(zhí)行“比較并交換”(CAS)操作,而該變量所在的緩存線在 CPU7 的高速緩存中什湘,就會發(fā)生以下經(jīng)過簡化的事件序列:

CPU0 檢查本地高速緩存长赞,沒有找到緩存線。

請求被轉(zhuǎn)發(fā)到 CPU0 和 CPU1 的互聯(lián)模塊禽炬,檢查 CPU1 的本地高速緩存涧卵,沒有找到緩存線。

請求被轉(zhuǎn)發(fā)到系統(tǒng)互聯(lián)模塊腹尖,檢查其他三個管芯柳恐,得知緩存線被 CPU6和 CPU7 所在的管芯持有。

請求被轉(zhuǎn)發(fā)到 CPU6 和 CPU7 的互聯(lián)模塊热幔,檢查這兩個 CPU 的高速緩存乐设,在 CPU7 的高速緩存中找到緩存線。

CPU7 將緩存線發(fā)送給所屬的互聯(lián)模塊绎巨,并且刷新自己高速緩存中的緩存線近尚。

CPU6 和 CPU7 的互聯(lián)模塊將緩存線發(fā)送給系統(tǒng)互聯(lián)模塊。

系統(tǒng)互聯(lián)模塊將緩存線發(fā)送給 CPU0 和 CPU1 的互聯(lián)模塊场勤。

CPU0 和 CPU1 的互聯(lián)模塊將緩存線發(fā)送給 CPU0 的高速緩存戈锻。

CPU0 現(xiàn)在可以對高速緩存中的變量執(zhí)行 CAS 操作了

以上是刷新不同CPU緩存的開銷歼跟。最好情況下的 CAS 操作消耗大概 40 納秒,超過 60 個時鐘周期格遭。這里的“最好情況”是指對某一個變量執(zhí)行 CAS 操作的 CPU 正好是最后一個操作該變量的CPU哈街,所以對應(yīng)的緩存線已經(jīng)在 CPU 的高速緩存中了,類似地拒迅,最好情況下的鎖操作(一個“round trip 對”包括獲取鎖和隨后的釋放鎖)消耗超過 60 納秒骚秦,超過 100 個時鐘周期。這里的“最好情況”意味著用于表示鎖的數(shù)據(jù)結(jié)構(gòu)已經(jīng)在獲取和釋放鎖的 CPU 所屬的高速緩存中了璧微。鎖操作比 CAS 操作更加耗時作箍,是因深入理解并行編程

為鎖操作的數(shù)據(jù)結(jié)構(gòu)中需要兩個原子操作。緩存未命中消耗大概 140 納秒前硫,超過 200 個時鐘周期胞得。需要在存儲新值時查詢變量的舊值的 CAS 操作,消耗大概 300 納秒开瞭,超過 500 個時鐘周期懒震。想想這個,在執(zhí)行一次 CAS 操作的時間里嗤详,CPU 可以執(zhí)行 500 條普通指令。這表明了細粒度鎖的局限性瓷炮。

以下是cache miss cas 和lock的性能對比:

JVM對CAS的支持:AtomicInt, AtomicLong.incrementAndGet()

在JDK1.5之前葱色,如果不編寫明確的代碼就無法執(zhí)行CAS操作,在JDK1.5中引入了底層的支持娘香,在int苍狰、long和對象的引用等類型上都公開了CAS的操作,并且JVM把它們編譯為底層硬件提供的最有效的方法烘绽,在運行CAS的平臺上淋昭,運行時把它們編譯為相應(yīng)的機器指令,如果處理器/CPU不支持CAS指令安接,那么JVM將使用自旋鎖翔忽。因此,值得注意的是盏檐,CAS解決方案與平臺/編譯器緊密相關(guān)(比如x86架構(gòu)下其對應(yīng)的匯編指令是lock cmpxchg歇式,如果想要64Bit的交換,則應(yīng)使用lock cmpxchg8b胡野。在.NET中我們可以使用Interlocked.CompareExchange函數(shù))材失。

在原子類變量中,如java.util.concurrent.atomic中的AtomicXXX硫豆,都使用了這些底層的JVM支持為數(shù)字類型的引用類型提供一種高效的CAS操作龙巨,而在java.util.concurrent中的大多數(shù)類在實現(xiàn)時都直接或間接的使用了這些原子變量類笼呆。

Java 1.6中AtomicLong.incrementAndGet()的實現(xiàn)源碼為:

+ View Code

由此可見,AtomicLong.incrementAndGet的實現(xiàn)用了樂觀鎖技術(shù)旨别,調(diào)用了sun.misc.Unsafe類庫里面的 CAS算法诗赌,用CPU指令來實現(xiàn)無鎖自增。所以昼榛,AtomicLong.incrementAndGet的自增比用synchronized的鎖效率倍增境肾。

public?final?int?getAndIncrement() {?

????????for?(;;) {?

????????????int?current = get();?

????????????int?next = current + 1;?

????????????if?(compareAndSet(current, next))?

????????????????return?current;?

????????}?

}?


public?final?boolean?compareAndSet(int?expect, int?update) {?

????return?unsafe.compareAndSwapInt(this, valueOffset, expect, update);?

}

下面是測試代碼:可以看到用AtomicLong.incrementAndGet的性能比用synchronized高出幾倍。

+ View Code

CAS的例子:非阻塞堆棧

下面是比非阻塞自增稍微復雜一點的CAS的例子:非阻塞堆棧/ConcurrentStack?胆屿。ConcurrentStack?中的?push()?和?pop()?操作在結(jié)構(gòu)上與NonblockingCounter?上相似奥喻,只是做的工作有些冒險,希望在 “提交” 工作的時候非迹,底層假設(shè)沒有失效环鲤。push()?方法觀察當前最頂?shù)墓?jié)點,構(gòu)建一個新節(jié)點放在堆棧上憎兽,然后冷离,如果最頂端的節(jié)點在初始觀察之后沒有變化,那么就安裝新節(jié)點纯命。如果 CAS 失敗西剥,意味著另一個線程已經(jīng)修改了堆棧,那么過程就會重新開始亿汞。

public?class?ConcurrentStack<E> {

????AtomicReference<Node<E>> head = new?AtomicReference<Node<E>>();

????public?void?push(E item) {

????????Node<E> newHead = new?Node<E>(item);

????????Node<E> oldHead;

????????do?{

????????????oldHead = head.get();

????????????newHead.next = oldHead;

????????} while?(!head.compareAndSet(oldHead, newHead));

????}

????public?E pop() {

????????Node<E> oldHead;

????????Node<E> newHead;

????????do?{

????????????oldHead = head.get();

????????????if?(oldHead == null)

????????????????return?null;

????????????newHead = oldHead.next;

????????} while?(!head.compareAndSet(oldHead,newHead));

????????return?oldHead.item;

????}

????static?class?Node<E> {

????????final?E item;

????????Node<E> next;

????????public?Node(E item) { this.item = item; }

????}

}

在輕度到中度的爭用情況下瞭空,非阻塞算法的性能會超越阻塞算法,因為 CAS 的多數(shù)時間都在第一次嘗試時就成功疗我,而發(fā)生爭用時的開銷也不涉及線程掛起和上下文切換咆畏,只多了幾個循環(huán)迭代。沒有爭用的 CAS 要比沒有爭用的鎖便宜得多(這句話肯定是真的吴裤,因為沒有爭用的鎖涉及 CAS 加上額外的處理)旧找,而爭用的 CAS 比爭用的鎖獲取涉及更短的延遲。

在高度爭用的情況下(即有多個線程不斷爭用一個內(nèi)存位置的時候)麦牺,基于鎖的算法開始提供比非阻塞算法更好的吞吐率钮蛛,因為當線程阻塞時,它就會停止爭用枕面,耐心地等候輪到自己愿卒,從而避免了進一步爭用。但是潮秘,這么高的爭用程度并不常見琼开,因為多數(shù)時候,線程會把線程本地的計算與爭用共享數(shù)據(jù)的操作分開枕荞,從而給其他線程使用共享數(shù)據(jù)的機會柜候。

CAS的例子3:非阻塞鏈表

以上的示例(自增計數(shù)器和堆棧)都是非常簡單的非阻塞算法搞动,一旦掌握了在循環(huán)中使用 CAS,就可以容易地模仿它們渣刷。對于更復雜的數(shù)據(jù)結(jié)構(gòu)鹦肿,非阻塞算法要比這些簡單示例復雜得多,因為修改鏈表辅柴、樹或哈希表可能涉及對多個指針的更新箩溃。CAS 支持對單一指針的原子性條件更新,但是不支持兩個以上的指針碌嘀。所以涣旨,要構(gòu)建一個非阻塞的鏈表、樹或哈希表股冗,需要找到一種方式霹陡,可以用 CAS 更新多個指針,同時不會讓數(shù)據(jù)結(jié)構(gòu)處于不一致的狀態(tài)止状。

在鏈表的尾部插入元素烹棉,通常涉及對兩個指針的更新:“尾” 指針總是指向列表中的最后一個元素,“下一個” 指針從過去的最后一個元素指向新插入的元素怯疤。因為需要更新兩個指針浆洗,所以需要兩個 CAS。在獨立的 CAS 中更新兩個指針帶來了兩個需要考慮的潛在問題:如果第一個 CAS 成功集峦,而第二個 CAS 失敗辅髓,會發(fā)生什么?如果其他線程在第一個和第二個 CAS 之間企圖訪問鏈表少梁,會發(fā)生什么?

對于非復雜數(shù)據(jù)結(jié)構(gòu)矫付,構(gòu)建非阻塞算法的 “技巧” 是確保數(shù)據(jù)結(jié)構(gòu)總處于一致的狀態(tài)(甚至包括在線程開始修改數(shù)據(jù)結(jié)構(gòu)和它完成修改之間)凯沪,還要確保其他線程不僅能夠判斷出第一個線程已經(jīng)完成了更新還是處在更新的中途,還能夠判斷出如果第一個線程走向 AWOL买优,完成更新還需要什么操作妨马。如果線程發(fā)現(xiàn)了處在更新中途的數(shù)據(jù)結(jié)構(gòu),它就可以 “幫助” 正在執(zhí)行更新的線程完成更新杀赢,然后再進行自己的操作烘跺。當?shù)谝粋€線程回來試圖完成自己的更新時,會發(fā)現(xiàn)不再需要了脂崔,返回即可滤淳,因為 CAS 會檢測到幫助線程的干預(在這種情況下,是建設(shè)性的干預)砌左。

這種 “幫助鄰居” 的要求脖咐,對于讓數(shù)據(jù)結(jié)構(gòu)免受單個線程失敗的影響铺敌,是必需的。如果線程發(fā)現(xiàn)數(shù)據(jù)結(jié)構(gòu)正處在被其他線程更新的中途屁擅,然后就等候其他線程完成更新偿凭,那么如果其他線程在操作中途失敗,這個線程就可能永遠等候下去派歌。即使不出現(xiàn)故障弯囊,這種方式也會提供糟糕的性能,因為新到達的線程必須放棄處理器胶果,導致上下文切換匾嘱,或者等到自己的時間片過期(而這更糟)。

public?class?LinkedQueue <E> {

????private?static?class?Node <E> {

????????final?E item;

????????final?AtomicReference<Node<E>> next;

????????Node(E item, Node<E> next) {

????????????this.item = item;

????????????this.next = new?AtomicReference<Node<E>>(next);

????????}

????}

????private?AtomicReference<Node<E>> head

????????= new?AtomicReference<Node<E>>(new?Node<E>(null, null));

????private?AtomicReference<Node<E>> tail = head;

????public?boolean?put(E item) {

????????Node<E> newNode = new?Node<E>(item, null);

????????while?(true) {

????????????Node<E> curTail = tail.get();

????????????Node<E> residue = curTail.next.get();

????????????if?(curTail == tail.get()) {

????????????????if?(residue == null) /* A */?{

????????????????????if?(curTail.next.compareAndSet(null, newNode)) /* C */?{

????????????????????????tail.compareAndSet(curTail, newNode) /* D */?;

????????????????????????return?true;

????????????????????}

????????????????} else?{

????????????????????tail.compareAndSet(curTail, residue) /* B */;

????????????????}

????????????}

????????}

????}

}

具體算法詳見IBM Developerworks

Java的ConcurrentHashMap的實現(xiàn)原理

Java5中的ConcurrentHashMap稽物,線程安全奄毡,設(shè)計巧妙,用桶粒度的鎖贝或,避免了put和get中對整個map的鎖定吼过,尤其在get中,只對一個HashEntry做鎖定操作咪奖,性能提升是顯而易見的盗忱。

具體實現(xiàn)中使用了鎖分離機制,在這個帖子中有非常詳細的討論羊赵。這里有關(guān)于Java內(nèi)存模型結(jié)合ConcurrentHashMap的分析趟佃。以下是JDK6的ConcurrentHashMap的源碼:

+ View Code

Java的ConcurrentLinkedQueue實現(xiàn)方法

ConcurrentLinkedQueue也是同樣使用了CAS指令,但其性能并不高因為太多CAS操作昧捷。其源碼如下:

+ View Code

高并發(fā)環(huán)境下優(yōu)化鎖或無鎖(lock-free)的設(shè)計思路

服務(wù)端編程的3大性能殺手:1闲昭、大量線程導致的線程切換開銷。2靡挥、鎖序矩。3、非必要的內(nèi)存拷貝跋破。在高并發(fā)下,對于純內(nèi)存操作來說,單線程是要比多線程快的, 可以比較一下多線程程序在壓力測試下cpu的sy和ni百分比簸淀。高并發(fā)環(huán)境下要實現(xiàn)高吞吐量和線程安全,兩個思路:一個是用優(yōu)化的鎖實現(xiàn)毒返,一個是lock-free的無鎖結(jié)構(gòu)租幕。但非阻塞算法要比基于鎖的算法復雜得多。開發(fā)非阻塞算法是相當專業(yè)的訓練拧簸,而且要證明算法的正確也極為困難劲绪,不僅和具體的目標機器平臺和編譯器相關(guān),而且需要復雜的技巧和嚴格的測試。雖然Lock-Free編程非常困難珠叔,但是它通承睿可以帶來比基于鎖編程更高的吞吐量。所以Lock-Free編程是大有前途的技術(shù)祷安。它在線程中止姥芥、優(yōu)先級倒置以及信號安全等方面都有著良好的表現(xiàn)。

優(yōu)化鎖實現(xiàn)的例子:Java中的ConcurrentHashMap汇鞭,設(shè)計巧妙凉唐,用桶粒度的鎖和鎖分離機制,避免了put和get中對整個map的鎖定霍骄,尤其在get中台囱,只對一個HashEntry做鎖定操作,性能提升是顯而易見的(詳細分析見《探索 ConcurrentHashMap 高并發(fā)性的實現(xiàn)機制》)读整。

Lock-free無鎖的例子:CAS(CPU的Compare-And-Swap指令)的利用和LMAX的disruptor無鎖消息隊列數(shù)據(jù)結(jié)構(gòu)等簿训。有興趣了解LMAX的disruptor無鎖消息隊列數(shù)據(jù)結(jié)構(gòu)的可以移步slideshare。

disruptor無鎖消息隊列數(shù)據(jù)結(jié)構(gòu)的類圖和技術(shù)文檔下載

另外米间,在設(shè)計思路上除了盡量減少資源爭用以外强品,還可以借鑒nginx/node.js等單線程大循環(huán)的機制,用單線程或CPU數(shù)相同的線程開辟大的隊列屈糊,并發(fā)的時候任務(wù)壓入隊列的榛,線程輪詢?nèi)缓笠粋€個順序執(zhí)行。由于每個都采用異步I/O逻锐,沒有阻塞線程夫晌。這個大隊列可以使用RabbitMQueue,或是JDK的同步隊列(性能稍差)昧诱,或是使用Disruptor無鎖隊列(Java)晓淀。任務(wù)處理可以全部放在內(nèi)存(多級緩存、讀寫分離盏档、ConcurrentHashMap要糊、甚至分布式緩存Redis)中進行增刪改查。最后用Quarz維護定時把緩存數(shù)據(jù)同步到DB中妆丘。當然,這只是中小型系統(tǒng)的思路局劲,如果是大型分布式系統(tǒng)會非常復雜勺拣,需要分而治理,用SOA的思路鱼填,參考這篇文章的圖药有。(注:Redis是單線程的純內(nèi)存數(shù)據(jù)庫,單線程無需鎖,而Memcache是多線程的帶CAS算法愤惰,兩者都使用epoll苇经,no-blocking io)

深入JVM的OS的無鎖非阻塞算法

如果深入 JVM 和操作系統(tǒng),會發(fā)現(xiàn)非阻塞算法無處不在宦言。垃圾收集器使用非阻塞算法加快并發(fā)和平行的垃圾搜集扇单;調(diào)度器使用非阻塞算法有效地調(diào)度線程和進程,實現(xiàn)內(nèi)在鎖奠旺。在 Mustang(Java 6.0)中蜘澜,基于鎖的?SynchronousQueue?算法被新的非阻塞版本代替。很少有開發(fā)人員會直接使用?SynchronousQueue响疚,但是通過?Executors.newCachedThreadPool()?工廠構(gòu)建的線程池用它作為工作隊列鄙信。比較緩存線程池性能的對比測試顯示,新的非阻塞同步隊列實現(xiàn)提供了幾乎是當前實現(xiàn) 3 倍的速度忿晕。在 Mustang 的后續(xù)版本(代碼名稱為 Dolphin)中装诡,已經(jīng)規(guī)劃了進一步的改進。

?著作權(quán)歸作者所有,轉(zhuǎn)載或內(nèi)容合作請聯(lián)系作者
  • 序言:七十年代末践盼,一起剝皮案震驚了整個濱河市鸦采,隨后出現(xiàn)的幾起案子,更是在濱河造成了極大的恐慌宏侍,老刑警劉巖赖淤,帶你破解...
    沈念sama閱讀 211,123評論 6 490
  • 序言:濱河連續(xù)發(fā)生了三起死亡事件,死亡現(xiàn)場離奇詭異谅河,居然都是意外死亡咱旱,警方通過查閱死者的電腦和手機,發(fā)現(xiàn)死者居然都...
    沈念sama閱讀 90,031評論 2 384
  • 文/潘曉璐 我一進店門绷耍,熙熙樓的掌柜王于貴愁眉苦臉地迎上來吐限,“玉大人,你說我怎么就攤上這事褂始≈畹洌” “怎么了?”我有些...
    開封第一講書人閱讀 156,723評論 0 345
  • 文/不壞的土叔 我叫張陵崎苗,是天一觀的道長狐粱。 經(jīng)常有香客問我,道長胆数,這世上最難降的妖魔是什么肌蜻? 我笑而不...
    開封第一講書人閱讀 56,357評論 1 283
  • 正文 為了忘掉前任,我火速辦了婚禮必尼,結(jié)果婚禮上蒋搜,老公的妹妹穿的比我還像新娘篡撵。我一直安慰自己,他們只是感情好豆挽,可當我...
    茶點故事閱讀 65,412評論 5 384
  • 文/花漫 我一把揭開白布育谬。 她就那樣靜靜地躺著,像睡著了一般帮哈。 火紅的嫁衣襯著肌膚如雪膛檀。 梳的紋絲不亂的頭發(fā)上,一...
    開封第一講書人閱讀 49,760評論 1 289
  • 那天但汞,我揣著相機與錄音宿刮,去河邊找鬼。 笑死私蕾,一個胖子當著我的面吹牛僵缺,可吹牛的內(nèi)容都是我干的。 我是一名探鬼主播踩叭,決...
    沈念sama閱讀 38,904評論 3 405
  • 文/蒼蘭香墨 我猛地睜開眼磕潮,長吁一口氣:“原來是場噩夢啊……” “哼!你這毒婦竟也來了容贝?” 一聲冷哼從身側(cè)響起自脯,我...
    開封第一講書人閱讀 37,672評論 0 266
  • 序言:老撾萬榮一對情侶失蹤,失蹤者是張志新(化名)和其女友劉穎斤富,沒想到半個月后膏潮,有當?shù)厝嗽跇淞掷锇l(fā)現(xiàn)了一具尸體,經(jīng)...
    沈念sama閱讀 44,118評論 1 303
  • 正文 獨居荒郊野嶺守林人離奇死亡满力,尸身上長有42處帶血的膿包…… 初始之章·張勛 以下內(nèi)容為張勛視角 年9月15日...
    茶點故事閱讀 36,456評論 2 325
  • 正文 我和宋清朗相戀三年焕参,在試婚紗的時候發(fā)現(xiàn)自己被綠了。 大學時的朋友給我發(fā)了我未婚夫和他白月光在一起吃飯的照片油额。...
    茶點故事閱讀 38,599評論 1 340
  • 序言:一個原本活蹦亂跳的男人離奇死亡叠纷,死狀恐怖,靈堂內(nèi)的尸體忽然破棺而出潦嘶,到底是詐尸還是另有隱情涩嚣,我是刑警寧澤,帶...
    沈念sama閱讀 34,264評論 4 328
  • 正文 年R本政府宣布掂僵,位于F島的核電站航厚,受9級特大地震影響,放射性物質(zhì)發(fā)生泄漏锰蓬。R本人自食惡果不足惜阶淘,卻給世界環(huán)境...
    茶點故事閱讀 39,857評論 3 312
  • 文/蒙蒙 一、第九天 我趴在偏房一處隱蔽的房頂上張望互妓。 院中可真熱鬧,春花似錦、人聲如沸冯勉。這莊子的主人今日做“春日...
    開封第一講書人閱讀 30,731評論 0 21
  • 文/蒼蘭香墨 我抬頭看了看天上的太陽灼狰。三九已至宛瞄,卻和暖如春,著一層夾襖步出監(jiān)牢的瞬間交胚,已是汗流浹背份汗。 一陣腳步聲響...
    開封第一講書人閱讀 31,956評論 1 264
  • 我被黑心中介騙來泰國打工, 沒想到剛下飛機就差點兒被人妖公主榨干…… 1. 我叫王不留蝴簇,地道東北人杯活。 一個月前我還...
    沈念sama閱讀 46,286評論 2 360
  • 正文 我出身青樓,卻偏偏與公主長得像熬词,于是被迫代替她去往敵國和親旁钧。 傳聞我的和親對象是個殘疾皇子,可洞房花燭夜當晚...
    茶點故事閱讀 43,465評論 2 348