溫馨提示×

溫馨提示×

您好,登錄后才能下訂單哦!

密碼登錄×
登錄注冊×
其他方式登錄
點擊 登錄注冊 即表示同意《億速云用戶服務(wù)條款》

Java 8中的StampedLock是否將是解決同步問題的關(guān)鍵

發(fā)布時間:2021-09-18 17:08:46 來源:億速云 閱讀:94 作者:柒染 欄目:編程語言

Java 8中的StampedLock是否將是解決同步問題的關(guān)鍵,相信很多沒有經(jīng)驗的人對此束手無策,為此本文總結(jié)了問題出現(xiàn)的原因和解決方法,通過這篇文章希望你能解決這個問題。

Java8就像一個寶藏,一個小的API改進,也足與寫一篇文章,比如同步,一直是多線程并發(fā)編程的一個老話題,相信沒有人喜歡同步的代碼,這會降低應(yīng)用的吞吐量等性能指標,最壞的時候會掛起死機,但是即使這樣你也沒得選擇,因為要保證信息的正確性。所以小編決定將從synchronized、Lock到Java8新增的StampedLock進行對比分析,相信StampedLock不會讓大家失望。

synchronized

在java5之前,實現(xiàn)同步主要是使用synchronized。它是Java語言的關(guān)鍵字,當它用來修飾一個方法或者一個代碼塊的時候,能夠保證在同一時刻最多只有一個線程執(zhí)行該段代碼。

有四種不同的同步塊:

  1. 實例方法

  2. 靜態(tài)方法

  3. 實例方法中的同步塊

  4. 靜態(tài)方法中的同步塊

大家對此應(yīng)該不陌生,所以不多講了,以下是代碼示例

synchronized(this)  // do operation  }

小結(jié):在多線程并發(fā)編程中Synchronized一直是元老級角色,很多人都會稱呼它為重量級鎖,但是隨著Java SE1.6對Synchronized進行了各種優(yōu)化之后,性能上也有所提升。

Lock

它是Java 5在java.util.concurrent.locks新增的一個API。

Lock是一個接口,核心方法是lock(),unlock(),tryLock(),實現(xiàn)類有ReentrantLock, ReentrantReadWriteLock.ReadLock, ReentrantReadWriteLock.WriteLock;

ReentrantReadWriteLock, ReentrantLock 和synchronized鎖都有相同的內(nèi)存語義。

與synchronized不同的是,Lock完全用Java寫成,在java這個層面是無關(guān)JVM實現(xiàn)的。Lock提供更靈活的鎖機制,很多synchronized 沒有提供的許多特性,比如鎖投票,定時鎖等候和中斷鎖等候,但因為lock是通過代碼實現(xiàn)的,要保證鎖定一定會被釋放,就必須將unLock()放到finally{}中

下面是Lock的一個代碼示例

rwlock.writeLock().lock();  try {  // do operation  } finally {  rwlock.writeLock().unlock();  }

小結(jié):比synchronized更靈活、更具可伸縮性的鎖定機制,但不管怎么說還是synchronized代碼要更容易書寫些

StampedLock

它是java8在java.util.concurrent.locks新增的一個API。

ReentrantReadWriteLock 在沒有任何讀寫鎖時,才可以取得寫入鎖,這可用于實現(xiàn)了悲觀讀取(Pessimistic Reading),即如果執(zhí)行中進行讀取時,經(jīng)??赡苡辛硪粓?zhí)行要寫入的需求,為了保持同步,ReentrantReadWriteLock 的讀取鎖定就可派上用場。

然而,如果讀取執(zhí)行情況很多,寫入很少的情況下,使用 ReentrantReadWriteLock 可能會使寫入線程遭遇饑餓(Starvation)問題,也就是寫入線程吃吃無法競爭到鎖定而一直處于等待狀態(tài)。

StampedLock控制鎖有三種模式(寫,讀,樂觀讀),一個StampedLock狀態(tài)是由版本和模式兩個部分組成,鎖獲取方法返回一個數(shù)字作為票據(jù)stamp,它用相應(yīng)的鎖狀態(tài)表示并控制訪問,數(shù)字0表示沒有寫鎖被授權(quán)訪問。在讀鎖上分為悲觀鎖和樂觀鎖。

所謂的樂觀讀模式,也就是若讀的操作很多,寫的操作很少的情況下,你可以樂觀地認為,寫入與讀取同時發(fā)生幾率很少,因此不悲觀地使用完全的讀取鎖定,程序可以查看讀取資料之后,是否遭到寫入執(zhí)行的變更,再采取后續(xù)的措施(重新讀取變更信息,或者拋出異常) ,這一個小小改進,可大幅度提高程序的吞吐量??!

下面是java doc提供的StampedLock一個例子

class Point {     private double x, y;     private final StampedLock sl = new StampedLock();     void move(double deltaX, double deltaY) { // an exclusively locked method       long stamp = sl.writeLock();       try {         x += deltaX;         y += deltaY;       } finally {         sl.unlockWrite(stamp);       }     }    //下面看看樂觀讀鎖案例     double distanceFromOrigin() { // A read-only method       long stamp = sl.tryOptimisticRead(); //獲得一個樂觀讀鎖       double currentX = x, currentY = y; //將兩個字段讀入本地局部變量       if (!sl.validate(stamp)) { //檢查發(fā)出樂觀讀鎖后同時是否有其他寫鎖發(fā)生?          stamp = sl.readLock(); //如果沒有,我們再次獲得一個讀悲觀鎖          try {            currentX = x; // 將兩個字段讀入本地局部變量            currentY = y; // 將兩個字段讀入本地局部變量          } finally {             sl.unlockRead(stamp);          }       }       return Math.sqrt(currentX * currentX + currentY * currentY);     }  //下面是悲觀讀鎖案例     void moveIfAtOrigin(double newX, double newY) { // upgrade       // Could instead start with optimistic, not read mode       long stamp = sl.readLock();       try {         while (x == 0.0 && y == 0.0) { //循環(huán),檢查當前狀態(tài)是否符合           long ws = sl.tryConvertToWriteLock(stamp); //將讀鎖轉(zhuǎn)為寫鎖           if (ws != 0L) { //這是確認轉(zhuǎn)為寫鎖是否成功             stamp = ws; //如果成功 替換票據(jù)             x = newX; //進行狀態(tài)改變             y = newY; //進行狀態(tài)改變             break;           }           else { //如果不能成功轉(zhuǎn)換為寫鎖             sl.unlockRead(stamp); //我們顯式釋放讀鎖             stamp = sl.writeLock(); //顯式直接進行寫鎖 然后再通過循環(huán)再試           }         }       } finally {         sl.unlock(stamp); //釋放讀鎖或?qū)戞i       }     }   }

小結(jié):

StampedLock要比ReentrantReadWriteLock更加廉價,也就是消耗比較小。

StampedLock與ReadWriteLock性能對比

下圖是和ReadWritLock相比,在一個線程情況下,是讀速度其4倍左右,寫是1倍。

Java 8中的StampedLock是否將是解決同步問題的關(guān)鍵

下圖是六個線程情況下,讀性能是其幾十倍,寫性能也是近10倍左右:

Java 8中的StampedLock是否將是解決同步問題的關(guān)鍵

下圖是吞吐量提高:

Java 8中的StampedLock是否將是解決同步問題的關(guān)鍵

總結(jié)

1、synchronized是在JVM層面上實現(xiàn)的,不但可以通過一些監(jiān)控工具監(jiān)控synchronized的鎖定,而且在代碼執(zhí)行時出現(xiàn)異常,JVM會自動釋放鎖定;

2、ReentrantLock、ReentrantReadWriteLock,、StampedLock都是對象層面的鎖定,要保證鎖定一定會被釋放,就必須將unLock()放到finally{}中;

3、StampedLock 對吞吐量有巨大的改進,特別是在讀線程越來越多的場景下;

4、StampedLock有一個復(fù)雜的API,對于加鎖操作,很容易誤用其他方法;

5、當只有少量競爭者的時候,synchronized是一個很好的通用的鎖實現(xiàn);

6、當線程增長能夠預(yù)估,ReentrantLock是一個很好的通用的鎖實現(xiàn);

StampedLock 可以說是Lock的一個很好的補充,吞吐量以及性能上的提升足以打動很多人了,但并不是說要替代之前Lock的東西,畢竟他還是有些應(yīng)用場景的,起碼API比StampedLock容易入手,下篇博文爭取更新快一點,可能會是Nashorn的內(nèi)容,這里允許我先賣個關(guān)子。。。

原文鏈接:http://my.oschina.net/benhaile/blog/264383

看完上述內(nèi)容,你們掌握Java 8中的StampedLock是否將是解決同步問題的關(guān)鍵的方法了嗎?如果還想學到更多技能或想了解更多相關(guān)內(nèi)容,歡迎關(guān)注億速云行業(yè)資訊頻道,感謝各位的閱讀!

向AI問一下細節(jié)

免責聲明:本站發(fā)布的內(nèi)容(圖片、視頻和文字)以原創(chuàng)、轉(zhuǎn)載和分享為主,文章觀點不代表本網(wǎng)站立場,如果涉及侵權(quán)請聯(lián)系站長郵箱:is@yisu.com進行舉報,并提供相關(guān)證據(jù),一經(jīng)查實,將立刻刪除涉嫌侵權(quán)內(nèi)容。

AI