本文從synchronized、Lock到Java8新增的StampedLock進行比較分析,對Java8新特性之StampedLock相關知識感興趣的朋友一起看看吧
Java8就像一個寶藏,一個小的API改進,也足與寫一篇文章,例如同步,一直是多線程並發編程的一個老話題,相信沒有人喜歡同步的代碼,這會降低應用的吞吐量等性能指標,最壞的時候會掛起死機,但是即使這樣你也沒得選擇,因為要確保資訊的正確性。所以這篇文章決定將從synchronized、Lock到Java8新增的StampedLock進行比較分析,相信StampedLock不會讓大家失望。
synchronized
在java5之前,實作同步主要是使用synchronized。它是Java語言的關鍵字,當它用來修飾一個方法或一個程式碼區塊的時候,能夠保證在同一時刻最多只有一個執行緒執行該段程式碼。
有四個不同的同步區塊:
1.實例方法
2.靜態方法
3.實例方法中的同步區塊
4.靜態方法中的同步區塊
大家對此應該不陌生,所以不多講了,以下是程式碼範例
synchronized(this) // do operation }
小結:在多線程並發編程中Synchronized一直是元老級角色,很多人都會稱呼它為重量級鎖,但是隨著Java SE1.6對Synchronized進行了各種優化之後,性能上也有所提升。
Lock
它是Java 5在java.util.concurrent.locks新增的一個API。
Lock是一個接口,核心方法是lock(),unlock(),tryLock(),實作類別有ReentrantLock, ReentrantReadWriteLock.ReadLock, ReentrantReadWriteLock.WriteLock;
ReentrantReadWriteLock,ReadWriteLock, ReentrantLock 和synchronized鎖都有相同的記憶體語意。
與synchronized不同的是,Lock完全用Java寫成,在java這個層面是無關JVM實現的。 Lock提供更靈活的鎖機制,很多synchronized 沒有提供的許多特性,例如鎖投票,定時鎖等候和中斷鎖等候,但因為lock是透過程式碼實現的,要保證鎖定一定會被釋放,就必須將unLock( )放到finally{}中
下面是Lock的一個程式碼範例
rwlock.writeLock().lock(); try { // do operation } finally { rwlock.writeLock().unlock(); }
小結:比synchronized更靈活、更具可擴展性的鎖定機制,但不管怎麼說還是synchronized程式碼要更容易書寫些
#StampedLock
##它是java8在java.util.concurrent.locks新增的一個API。拋出異常) ,這一個小小改進,可大幅度提高程式的吞吐量! !
下面是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)) { //检查发出乐观读锁后同时是否有其他写锁发生? 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) { //循环,检查当前状态是否符合 long ws = sl.tryConvertToWriteLock(stamp); //将读锁转为写锁 if (ws != 0L) { //这是确认转为写锁是否成功 stamp = ws; //如果成功 替换票据 x = newX; //进行状态改变 y = newY; //进行状态改变 break; } else { //如果不能成功转换为写锁 sl.unlockRead(stamp); //我们显式释放读锁 stamp = sl.writeLock(); //显式直接进行写锁 然后再通过循环再试 } } } finally { sl.unlock(stamp); //释放读锁或写锁 } } }
小結:
StampedLock要比ReentrantReadWriteLock更廉價,也就是消耗比較小。StampedLock與ReadWriteLock效能比較
下圖是和ReadWritLock相比,在一個執行緒情況下,是讀速度其4倍左右,寫是1倍。 下圖是六個執行緒情況下,讀取效能是其數十倍,寫入效能也是近10倍左右: 下圖是吞吐量提高:總結
#1、synchronized是在JVM層面上實現的,不但可以透過一些監控工具監控synchronized的鎖定,而且在程式碼執行時出現異常,JVM會自動釋放鎖定;
2、ReentrantLock、ReentrantReadWriteLock,、StampedLock都是物件層面的鎖定,要保證鎖定一定會被釋放,就必須將unLock()放到finally{}中;
3、StampedLock 對吞吐量有巨大的改進,特別是在讀取線程越來越多的場景下;
# 4.StampedLock有一個複雜的API,對於加鎖操作,很容易誤用其他方法;
#5、當只有少量競爭者的時候,synchronized是一個很好的通用的鎖定實現;
6、當執行緒成長能夠預估,ReentrantLock是一個很好的通用的鎖定實作;
以上是解讀Java8新特性--StampedLock的詳細內容。更多資訊請關注PHP中文網其他相關文章!