可重入鎖

原文: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. 參考文章



發表評論
所有評論
還沒有人評論,想成為第一個評論的人麼? 請在上方評論欄輸入並且點擊發布.
相關文章