Lock

一、JavaSE5的synchronized都是重量級的,而在JavaSE5以後出現了Lock接口以及相關接口來實現鎖的功能。並且在JavaSE6 中Lock性能和Lock性能相差無幾,可是synchronized能實現的功能Lock都能實現,緣由是Lock功能更全面。java

 

二、Lock接口提供的synchronized關鍵字不具有的主要特性有緩存

1)嘗試非阻塞地獲取鎖,經過 tryLock 進行非阻塞的嘗試獲取鎖併發

2)能被中斷地獲取鎖,經過lockInterruptibly 進行可中斷的競爭鎖,在鎖競爭過程當中能夠被中斷框架

3)超時獲取鎖,經過在tryLock獲取鎖時設置最大超時時間進行超時獲取工具

4)必須手工釋放鎖,由於synchronized代碼塊中發生異常會自動釋放鎖,可是Lock則不會。性能

5)獲取等待通知組件,經過調用 newCondition ,並且能夠有多個Condition.線程

 

三、使用Lock的僞代碼遞歸

Lock lock = new ReentrantLock();接口

lock.lock();get

try{

// do something.

}finally{

lock.unlock();

}

1)注意必須在finally裏面釋放鎖,緣由是Lock不會自動釋放

2)獲取鎖的過程最好寫在try外面,緣由是自定義的Lock可能在初始化Lock時發生異常,可能這個時候都尚未獲取到鎖,而後又調用釋放鎖,就會出現代碼異常。

 

四、重入鎖(ReentrantLock)

重入鎖是指支持重進入的鎖,也就是獲取鎖以後繼續獲取該鎖是不會被阻塞。synchronized隱式含有重入鎖,因此能夠遞歸調用synchronized修飾的方法也不會被阻塞等待。

ReetrantLock 還能夠支持公平鎖和非公平鎖,經過構造方法Boolean參數決定。

公平鎖是指先對鎖進行請求的鎖必定先被知足。這意味着等待時間最長的線程最有可能獲取到鎖,這樣能夠避免活鎖的發生。若是無論線程等待的時間任意分配鎖則是非公平鎖。

公平鎖和非公平鎖相對,公平性雖然保證了鎖的獲取按照了FIFO原則,而代價則是進行大量的線程切換,非公平鎖雖然可能形成線程出現活鎖的狀況,可是避免線程的切換能夠保證更大的吞吐量。

 

五、讀寫鎖(ReentrantReadWriteLock)

不管是synchronized仍是ReentrantLock都是排他鎖,在同一時刻只容許一個線程進行訪問,而讀寫鎖在同一時刻能夠運行多個讀線程同時訪問,可是在寫線程訪問時,全部的讀線程和其餘寫線程都被阻塞。

讀寫鎖維護了一對鎖,一個讀鎖和一個寫鎖,經過分離讀鎖和寫鎖,使得併發性相比通常的排他鎖有很大的提高。

讀寫鎖能夠降級(從寫鎖降級爲讀鎖),可是不能夠升級(從讀鎖升級爲寫鎖),爲何不能升級呢?是由於假設有多個線程同時獲取了讀鎖,忽然有一個線程升級爲寫鎖,那麼計算他修改了數據,可是其餘擁有讀鎖的線程讀取的數據可能不是最新的,避免髒讀數據因此不支持鎖的升級。

若是讀遠遠大於寫,那麼讀寫鎖可謂是最佳之選了,下面就是使用讀寫鎖實現緩存的代碼

private static Map<String,Object> cache = new HashMap<>();

private static ReadWriteLock lock = new ReentrantReadWriteLock();

private static Lock readLock = lock.readLock();

private static Lock writeLock = lock.writeLock();

public static Object get(String key){

readLock.lock();

try{

return cache.get(key);

}finally{

readLock.unlock();

}

}

public static void put(String key, Object value){

writeLock.lock();

try{

cache.put(key, value);

}finally{

writeLock.unlock();

}

}

 

六、LockSupport

LockSupport是JDK中比較底層的類,用來建立鎖和其餘同步工具類的基本線程阻塞原語。

java鎖和同步器框架的核心 AQS: AbstractQueuedSynchronizer,就是經過調用

LockSupport.park() 和 LockSupport.unpark()實現線程的阻塞和喚醒的。

LockSupport是可不重入。

示例代碼(一直阻塞在 start,除非被喚醒 ):

public static void main(String[] args) {

System.out.println("start");

LockSupport.park();

System.out.println("end.");

}

相關文章
相關標籤/搜索