摘要:測試吞吐量的時候,是通過每一種實現都重復測試超過次,每一次都運行秒以上,以保證系統足夠預熱,下面的結果都是第次之后平均每秒吞吐量。以我的經驗看,教學和開發中的無鎖算法,不僅能顯著改善吞吐量同時他們也提供更低的延遲。
上周在由Heinz Kabutz通過JCrete?組織的開放空間會議(unconference)上,我參加一個新的java規范 JSR166?StampedLock 的審查會議。 StampedLock 是為了解決多個readers?并發訪問共享狀態時,系統出現的內存地址競爭問題。在設計上通過使用樂觀的讀操作, StampedLock
比 ReentrantReadWriteLock 更加高效;
在會議期間,我突然意思到兩點:
我想是時候該去回顧java中鎖的實現的現狀。
雖然StampedLock 看上去是JDK很好的補充,但是似乎忽略了一個事實,即在多個reader的場景里,無鎖的算法通常是更好的解決方案。
測試為了比較不同的實現方式,我需要采用一種不偏向任意一方的API測試用例。 比如:API必須不產生垃圾、并且允許方法是原子性的。一個簡單的測試用例是設計一個可在兩維空間中移動其位置的太空船,它位置的坐標可以原子性的讀取;每一次事物里至少需要讀寫2個域,這使得并發變得非常有趣;
/** * 并發接口,表示太空船可以在2維的空間中移動位置;并且同時更新讀取位置 */ public interface Spaceship { /** * 讀取太空船的位置到參數數組 coordinates 中 * * @param coordinates 保存讀取到的XY坐標. * @return 當前的狀態 */ int readPosition(final int[] coordinates); /** * 通過增加XY的值表示移動太空船的位置。 * * @param xDelta x坐標軸上移動的增量. * @param yDelta y坐標軸上移動的增量. * @return the number of attempts made to write the new coordinates. */ int move(final int xDelta, final int yDelta); }
上面的API通過分解一個不變的位置對象,本身是干凈的。但是我想保證它不產生垃圾,并且需要能最直接的更新多個內容域。這個API可以很容易地擴展到三維空間,并實現原子性要求。
為每一個飛船都設置多個實現,并且作為一個測試套件。本文中所有的代碼和結果都可以在這里找到。
該測試套件會依次運行每一種實現.并且使用?megamorphic dispatch模式,防止并發訪問中的方法內聯(inlining),鎖粗化(lock-coarsening),循環展開(loop unrolling)的問題;
每種實現都執行下面4個不同的線程的情況,結果也是不同的;
1 reader – 1 writer 2 readers – 1 writer 3 readers – 1 writer 2 readers – 2 writers
所有的測試運行在64位機器、Java版本:1.7.0_25、 Linux版本:3.6.30、4核 2.2GHz Ivy Bridge (第三代Core i系列處理器)i7-3632QM的環境上。
測試吞吐量的時候,是通過每一種實現都重復測試超過5次,每一次都運行5秒以上,以保證系統足夠預熱,下面的結果都是第5次之后平均每秒吞吐量。為了更像一個典型的java應用;沒有采用會導致明顯減少差異的線程依附性(thread affinity)和多核隔離(core isolation?)技術;
結果上述圖表的原始數據可以在這里找到
分析結果里面真正令我吃驚的是ReentrantReadWriteLock的性能,我沒有想到的是,在這樣的場景下它在讀和少量寫之間取得的巨大的平衡性,
我主要的收獲:
StampedLock 對現存的鎖實現有巨大的改進,特別是在讀線程越來越多的場景下:
StampedLock有一個復雜的API,對于加鎖操作,很容易誤用其他方法;
當只有2個競爭者的時候,Synchronised是一個很好的通用的鎖實現;
當線程增長能夠預估,ReentrantLock是一個很好的通用的鎖實現;
選擇使用ReentrantReadWriteLock時,必須經過小心的適度的測試;所有重大的決定,必須在基于測試數據的基礎上做決定;
無鎖的實現比基于鎖的算法有更好短吞吐量;
結論:非常開心能看到無鎖技術對基于鎖的算法的影響; 樂觀鎖的策略,實際上就是一個無鎖算法技術。
以我的經驗看,教學和開發中的無鎖算法,不僅能顯著改善吞吐量;同時他們也提供更低的延遲。
原文 Lock based vs lock free concurrent
翻譯 曹姚君?校對 方騰飛
via ifeve
文章版權歸作者所有,未經允許請勿轉載,若此文章存在違規行為,您可以聯系管理員刪除。
轉載請注明本文地址:http://specialneedsforspecialkids.com/yun/64054.html
摘要:在本例中,講述的無鎖來自于并發包我們將這個無鎖的稱為。在這里,我們使用二維數組來表示的內部存儲,如下變量存放所有的內部元素。為什么使用二維數組去實現一個一維的呢這是為了將來進行動態擴展時可以更加方便。 我們已經比較完整得介紹了有關無鎖的概念和使用方法。相對于有鎖的方法,使用無鎖的方式編程更加考驗一個程序員的耐心和智力。但是,無鎖帶來的好處也是顯而易見的,第一,在高并發的情況下,它比有鎖...
摘要:因為多線程競爭鎖時會引起上下文切換。減少線程的使用。舉個例子如果說服務器的帶寬只有,某個資源的下載速度是,系統啟動個線程下載該資源并不會導致下載速度編程,所以在并發編程時,需要考慮這些資源的限制。 最近私下做一項目,一bug幾日未解決,總惶恐。一日頓悟,bug不可怕,怕的是項目不存在bug,與其懼怕,何不與其剛正面。 系列文章傳送門: Java多線程學習(一)Java多線程入門 Jav...
摘要:相比與其他操作系統包括其他類系統有很多的優點,其中有一項就是,其上下文切換和模式切換的時間消耗非常少。因為多線程競爭鎖時會引起上下文切換。減少線程的使用。很多編程語言中都有協程。所以如何避免死鎖的產生,在我們使用并發編程時至關重要。 系列文章傳送門: Java多線程學習(一)Java多線程入門 Java多線程學習(二)synchronized關鍵字(1) java多線程學習(二)syn...
摘要:本文旨在對鎖相關源碼本文中的源碼來自使用場景進行舉例,為讀者介紹主流鎖的知識點,以及不同的鎖的適用場景。中,關鍵字和的實現類都是悲觀鎖。自適應意味著自旋的時間次數不再固定,而是由前一次在同一個鎖上的自旋時間及鎖的擁有者的狀態來決定。 前言 Java提供了種類豐富的鎖,每種鎖因其特性的不同,在適當的場景下能夠展現出非常高的效率。本文旨在對鎖相關源碼(本文中的源碼來自JDK 8)、使用場景...
閱讀 1402·2021-11-22 09:34
閱讀 1378·2021-09-22 14:57
閱讀 3400·2021-09-10 10:50
閱讀 1371·2019-08-30 15:54
閱讀 3690·2019-08-29 17:02
閱讀 3472·2019-08-29 12:54
閱讀 2611·2019-08-27 10:57
閱讀 3316·2019-08-26 12:24