原文:https://www.shiyanlou.com/questions/2460
1 . 什麼是可重入鎖
鎖的概念就不用多解釋了,當某個線程A已經持有了一個鎖,當線程B嘗試進入被這個鎖保護的代碼段的時候.就會被阻塞.而鎖的操作粒度是”線程”,而不是調用(至於爲什麼要這樣,下面解釋).同一個線程再次進入同步代碼的時候.可以使用自己已經獲取到的鎖,這就是可重入鎖java裏面內置鎖(synchronize)和Lock(ReentrantLock)都是可重入的
2 . 爲什麼要可重入
如果線程A繼續再次獲得這個鎖呢?比如一個方法是synchronized,遞歸調用自己,那麼第一次已經獲得了鎖,第二次調用的時候還能進入嗎? 直觀上當然需要能進入.這就要求必須是可重入的.可重入鎖又叫做遞歸鎖,再舉個例子.
public class Widget {
public synchronized void doSomething() {
...
}
}
public class LoggingWidget extends Widget {
public synchronized void doSomething() {
System.out.println(toString() + ": calling doSomething");
super.doSomething();//若內置鎖是不可重入的,則發生死鎖
}
}
這個例子是java併發編程實戰中的例 子.synchronized 是父類Widget的內置鎖,當執行子 類的方法的時候,先獲取了一次Widget的鎖,然後在執行super的時候,就要獲取一次,如果不可重入,那麼就跪了.
3 . 如何實現可重入鎖
爲每個鎖關聯一個獲取計數器和一個所有者線程,當計數值爲0的時候,這個所就沒有被任何線程只有.當線程請求一個未被持有的鎖時,JVM將記下鎖的持有者,並且將獲取計數值置爲1,如果同一個線程再次獲取這個鎖,技術值將遞增,退出一次同步代碼塊,計算值遞減,當計數值爲0時,這個鎖就被釋放.ReentrantLock裏面有實現
4 . 有不可重入鎖嗎
這個還真有.Linux下的pthread_mutex_t鎖是默認是非遞歸的。可以通過設置PTHREAD_MUTEX_RECURSIVE屬性,將pthread_mutex_t鎖設置爲遞歸鎖。如果要自己實現不可重入鎖,同可重入鎖,這個計數器只能爲1.或者0,再次進入的時候,發現已經是1了,就進行阻塞.jdk裏面沒有默認的實現類.
5 . demo代碼展示
5.1 內置鎖的可重入
public class ReentrantTest {
public void method1() {
synchronized (ReentrantTest.class) {
System.out.println("方法1獲得ReentrantTest的內置鎖運行了");
method2();
}
}
public void method2() {
synchronized (ReentrantTest.class) {
System.out.println("方法1裏面調用的方法2重入內置鎖,也正常運行了");
}
}
public static void main(String[] args) {
new ReentrantTest().method1();
}
}
5.2 lock對象的可重入
import java.util.concurrent.locks.Lock;
import java.util.concurrent.locks.ReentrantLock;
public class ReentrantLockTest {
private Lock lock = new ReentrantLock();
public void method1() {
lock.lock();
try {
System.out.println("方法1獲得ReentrantLock鎖運行了");
method2();
} finally {
lock.unlock();
}
}
public void method2() {
lock.lock();
try {
System.out.println("方法1裏面調用的方法2重入ReentrantLock鎖,也正常運行了");
} finally {
lock.unlock();
}
}
public static void main(String[] args) {
new ReentrantLockTest().method1();
}
}
6. 參考文章