-
概述
什麼叫可重入鎖,簡而言之就是同一個線程可以多次擷取鎖而不被阻塞
- 使用舉例
public static void main(String[] args) {
for(int i=0;i<2;i++){
new Thread(new TestLock()).start();
}
System.out.println("建立線程完成");
//new Thread(new TestLock()).start();
}
private static class TestLock implements Runnable{
private static int a=0;
private static ReentrantLock reentrantLock = new ReentrantLock();
@Override
public void run() {
reentrantLock.lock();
a++;
try {
Thread.sleep(2000);
System.out.println(Thread.currentThread().getName()+"-a="+a);
} catch (InterruptedException e) {
e.printStackTrace();
}
reentrantLock.unlock();
}
}
這段代碼,執行的結果 會輸出一個 a=1 和 a=2(代碼可能不太嚴謹), 程式起了兩個線程,因為使用了鎖,是以a的值不會出現覆寫問題,會一個個線程排隊去執行.
- ReentrantLock構造
(五)JDK鎖源碼分析之可重入鎖ReentrantLock 我們看到這個構造,可能會看到比較奇怪, 裡面直接給一個sync的變量指派, 其實ReentrantLock就是一個代理而已,在調用lock方法,其實使用的真正lock方法是調用sync的,在
ReentrantLock内部有兩種實作如下:
(五)JDK鎖源碼分析之可重入鎖ReentrantLock 我們可以看到,兩個内部實作,都實作了lock方法,這個才是真正代理背後去擷取鎖的實作方法.(五)JDK鎖源碼分析之可重入鎖ReentrantLock
-lock方法(非公平方式)
在lock方法中首先通過原子操作去擷取鎖, 被鎖定的狀态下值大于0,沒被鎖定情況下狀态中為1, 如果擷取到鎖,那麼就會把目前線程設定為鎖持有的線程, 如果沒有擷取到鎖,那麼調用acquire方法進行等待,那麼是怎麼等待的呢?
acquire其實是父類(AbstractQueuedSynchronizer 同步器)的一個模版方法,具體怎麼去實作,根據鎖的特性去實作,acquire方法隻是作為一個主流程算法的一個控制,我們看看主流程
1.調用tryAcquire方法去嘗試擷取鎖, 同一個線程可以多次獲得鎖
2.首先調用addWaiter方法使用尾插法将任務加入到隊列,然後方法acquireQueued使用cas算法去輪訓擷取鎖,阻塞目前線程
-
unlock方法
unlock方法原理很簡單,就是直接去釋放鎖,也就是把目前狀态值進行一個減少,減到0就表示目前線程已經釋放鎖,這個釋放鎖是不需要做線程安全的, 因為重入鎖是一種獨占鎖,在沒釋放前提下,其他線程都是被阻塞的,是以釋放鎖操作會簡單許多,隻是狀态值進行減小
(五)JDK鎖源碼分析之可重入鎖ReentrantLock (五)JDK鎖源碼分析之可重入鎖ReentrantLock 直接将狀态值減少,這是重入鎖的特性,狀态值會大于1,有個線程可以重複擷取鎖(五)JDK鎖源碼分析之可重入鎖ReentrantLock