一、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.");
}