【JavaSE】Lock鎖和synchronized鎖的比較,lock鎖的特性,讀寫鎖的實現。
一、為什麼出現了Lock鎖
出現lock鎖肯定是由於synchronized鎖有一些缺陷,下面說一下具體缺陷:
1. 不提供中斷鎖
synchronized鎖有兩種情況會釋放鎖:
①.程式碼塊或者方法執行完畢,自動釋放鎖
②.在執行程式碼塊或者方法過程中發生異常,自動釋放鎖.
那麼如果在執行過程中要等待IO或者其他原因被阻塞了,但是又沒有其他方法釋放鎖,其他執行緒只能繼續等待,這是非常影響程式效率的。
lock鎖提供了一些超時中斷和響應中斷的方法,讓等待獲取鎖的執行緒不會傻傻的等下去,可以幹一些別的事情
2.不能很好的實現讀寫操作
同時進行讀操作不需要互斥,讀寫操作和寫寫操作應該被互斥。但是用synchronized鎖的時候,讀操作和讀操作也沒互斥了,這樣就達不到我們的預期效果。但是lock鎖卻可以很好的實現讀寫操作。
需要注意
lock鎖和synchronized鎖最大的不同在於,內檢鎖是自動釋放鎖的,而lock鎖是需要手動呼叫方法去釋放鎖的,所以為了防止發生異常中斷而鎖卻沒有釋放,lock鎖的釋放一般都放在finally程式碼塊中。
二、Lock是一個介面
先看一下Lock介面中的方法:
public interface Lock {
void lock();
void lockInterruptibly() throws InterruptedException;
boolean tryLock();
boolean tryLock(long time, TimeUnit unit) throws InterruptedException;
void unlock();
Condition newCondition();
}
- 首先lock()方法是平常使用得最多的一個方法,就是用來獲取鎖。如果鎖已被其他執行緒獲取,則進行等待。
- lockInterruptibly()方法可以讓等待的執行緒響應中斷,如果執行緒A和執行緒B同時競爭鎖,執行緒B沒有搶到鎖進行等待,這時候對執行緒B呼叫threadB.interrupt()方法能夠中斷B的等待過程。
- tryLock()方法是嘗試獲取鎖,如果當前鎖是空閒的,或者當前執行緒持有鎖(可重入),就返回true表示當前執行緒獲取到鎖,否則就返回false,不會進行等待。
- tryLock(long time, TimeUnit unit)方法是在tryLock()方法的基礎上加入了一個等待時間作為引數,它沒有獲取到鎖會等待一定時間,如果超過這個時間還沒有獲取到鎖就返回false。
- unlock()是進行鎖的釋放,注意重入鎖幾次,就要釋放幾次。
三、實現Lock介面的子類
我們一般使用的兩個子類是:ReentrantLock鎖和ReentrantReadWriteLock鎖
1.ReentrantLock鎖
ReentrantLock是和synchronized鎖一樣的互斥鎖,具有相同的功能,但是有更好的擴充套件性。
①.構造方法
看一個類先看構造方法:
public ReentrantLock() {
sync = new NonfairSync();
}
public ReentrantLock(boolean fair) {
sync = fair ? new FairSync() : new NonfairSync();
}
有兩個構造方法,可以看到無參的時候,預設使用的是非公平的鎖。而傳入引數是true的話,使用的就是公平鎖了。
公平鎖:當鎖被釋放的時候,在所有等待鎖的執行緒裡面選用等待時間最長的執行緒。
非公平鎖:選取執行緒沒有規則。這樣線上程數量非常多的時候,有可能導致有的執行緒無限的等待下去。內建鎖使用的就是非公平鎖
②實現介面的方法
public void lock() {
sync.lock();
}
public void lockInterruptibly() throws InterruptedException {
sync.acquireInterruptibly(1);
}
public boolean tryLock() {
return sync.nonfairTryAcquire(1);
}
public boolean tryLock(long timeout, TimeUnit unit)
throws InterruptedException {
return sync.tryAcquireNanos(1, unit.toNanos(timeout));
}
public void unlock() {
sync.release(1);
}
public Condition newCondition() {
return sync.newCondition();
}
通過原始碼發現,每一個介面的方法,都是呼叫了sync變數的方法,而sync變數是在呼叫ReentrantLock構造方法的時候(假設呼叫無參構造),由NonfairSync()例項化而來。NonfairSync()又繼承了Sync類。
static final class NonfairSync extends Sync
Sync類是ReentrantLock類的一個靜態內部類:
abstract static class Sync extends AbstractQueuedSynchronizer
Sync繼承了AbstractQueuedSynchronizer,簡稱AQS它是一個同步器,AQS定義了一套多執行緒訪問共享資源的同步器框架,許多同步類實現都依賴於它。在下一篇部落格我會講解一下Lock鎖的原始碼是如何結合AQS實現的。
③.擴充套件的方法。
除了實現介面的方法,ReentrantLock類擴充套件了一些方法,包括檢視是否有執行緒在排隊等待鎖,檢視某個執行緒是否在排隊等待鎖,檢視是否有執行緒在等待佇列中,返回正在等待獲取此鎖執行緒數,和返回所有正等待獲取此鎖的執行緒。
1.ReentrantReadWriteLock鎖
這是一個介面:
public interface ReadWriteLock {
/**
* Returns the lock used for reading.
*
* @return the lock used for reading
*/
Lock readLock();
/**
* Returns the lock used for writing.
*
* @return the lock used for writing
*/
Lock writeLock();
}
一個用來獲取讀鎖,一個用來獲取寫鎖。也就是說將檔案的讀寫操作分開,分成2個鎖來分配給執行緒,從而使得多個執行緒可以同時進行讀操作。下面的ReentrantReadWriteLock實現了ReadWriteLock介面。
public class ReentrantReadWriteLock implements ReadWriteLock, java.io.Serializable
這個類的方法也是依靠Sync內部靜態類來實現的,不過ReentrantReadWriteLock可以實現讀鎖和讀鎖的執行緒不互斥,而讀鎖和寫鎖、寫鎖和寫鎖的執行緒之間互斥的特性。
四、Lock和synchronized的選擇
總結來說,Lock和synchronized有以下幾點不同:
1)Lock是一個介面,而synchronized是Java中的關鍵字,synchronized是內建的語言實現;
2)synchronized在發生異常時,會自動釋放執行緒佔有的鎖,因此不會導致死鎖現象發生;而Lock在發生異常時,如果沒有主動通過unLock()去釋放鎖,則很可能造成死鎖現象,因此使用Lock時需要在finally塊中釋放鎖;
3)Lock可以讓等待鎖的執行緒響應中斷,而synchronized卻不行,使用synchronized時,等待的執行緒會一直等待下去,不能夠響應中斷;
4)通過Lock可以知道有沒有成功獲取鎖,而synchronized卻無法辦到。
5)Lock可以提高多個執行緒進行讀操作的效率。
在效能上來說,如果競爭資源不激烈,兩者的效能是差不多的,而當競爭資源非常激烈時(即有大量執行緒同時競爭),此時Lock的效能要遠遠優於synchronized。所以說,在具體使用時要根據適當情況選擇。
相關文章
- Lock的獨佔鎖和共享鎖的比較分析
- Lock鎖之重入鎖與讀寫鎖
- Lock介面、重入鎖ReentrantLock、讀寫鎖ReentrantReadWriteLockReentrantLock
- Lock、Synchronized鎖區別解析synchronized
- java裡的鎖總結(synchronized隱式鎖、Lock顯式鎖、volatile、CAS)Javasynchronized
- Lock 鎖
- 淺談Java中的鎖:Synchronized、重入鎖、讀寫鎖Javasynchronized
- synchronized Lock(本地同步)鎖的8種情況synchronized
- Java併發指南4:Java中的鎖 Lock和synchronizedJavasynchronized
- 分散式鎖-Redission-Lock鎖的使用與原理分散式Redis
- java的乾兒子鎖LockJava
- ObjC 多執行緒簡析(二)- os_unfair_lock的型別和自旋鎖與互斥鎖的比較OBJ執行緒AI型別
- 【JavaSE】Lock鎖,獨佔鎖ReentrantLock的AQS原始碼,如何管理同步佇列。acquire方法和release方法JavaReentrantLockAQS原始碼佇列UI
- MySQL 共享鎖 (lock in share mode),排他鎖 (for update)MySql
- MySQL內部實現讀鎖和寫鎖的具體鎖定型別介紹MySql型別
- 鎖——Lock、Condition、ReadWriteLock、LockSupport
- mysql innodb lock鎖之record lock之一MySql
- 帶你理解Lock鎖原理
- Lock鎖相關以及AQSAQS
- 關於 ReentrantLock 中鎖 lock() 和解鎖 unlock() 的底層原理淺析ReentrantLock
- 讀寫鎖 ReentrantReadWriteLock 與 互斥鎖 的效率
- MySQL MyISAM引擎的讀鎖與寫鎖MySql
- Go語言中的互斥鎖和讀寫鎖(Mutex和RWMutex)GoMutex
- synchronized 鎖的原理synchronized
- mysql metadata lock後設資料鎖之鎖狀態lock_status流轉圖MySql
- MySQL-lock(鎖)-v2.0MySql
- TortoiseSvn強制解鎖 break lock
- mysql觀測METADATA LOCK(MDL)鎖MySql
- ThunderSoft File Lock for Mac檔案鎖Mac
- 自旋鎖、阻塞鎖、可重入鎖、悲觀鎖、樂觀鎖、讀寫鎖、偏向所、輕量級鎖、重量級鎖、鎖膨脹、物件鎖和類鎖物件
- synchronized類鎖與物件鎖synchronized物件
- 【JavaSE】淺談偏向鎖、輕量級鎖和重量級鎖,如何獲取鎖,如何撤銷鎖。Java
- synchronized鎖的升級synchronized
- MySQL鎖(讀鎖、共享鎖、寫鎖、S鎖、排它鎖、獨佔鎖、X鎖、表鎖、意向鎖、自增鎖、MDL鎖、RL鎖、GL鎖、NKL鎖、插入意向鎖、間隙鎖、頁鎖、悲觀鎖、樂觀鎖、隱式鎖、顯示鎖、全域性鎖、死鎖)MySql
- 利用MySQL中的樂觀鎖和悲觀鎖實現分散式鎖MySql分散式
- 讀寫鎖
- Java中的讀/寫鎖Java
- 面試官:你說說互斥鎖、自旋鎖、讀寫鎖、悲觀鎖、樂觀鎖的應用場景面試