Java可重入鎖學習筆記

目錄

  1. 什麼是可重入鎖
  2. 爲何要可重入
  3. 如何實現可重入鎖
  4. 有不可重入鎖嗎
  5. demo代碼展現
  6. 參考文章

1 . 什麼是可重入鎖

鎖的概念就不用多解釋了,當某個線程A已經持有了一個鎖,當線程B嘗試進入被這個鎖保護的代碼段的時候.就會被阻塞.而鎖的操做粒度是」線程」,而不是調用(至於爲何要這樣,下面解釋).同一個線程再次進入同步代碼的時候.可使用本身已經獲取到的鎖,這就是可重入鎖
java裏面內置鎖(synchronize)和Lock(ReentrantLock)都是可重入的html

2 . 爲何要可重入

若是線程A繼續再次得到這個鎖呢?好比一個方法是synchronized,遞歸調用本身,那麼第一次已經得到了鎖,第二次調用的時候還能進入嗎? 直觀上固然須要能進入.這就要求必須是可重入的.可重入鎖又叫作遞歸鎖,再舉個例子.java

1
2
3
4
5
6
7
8
9
10
11
12
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的時候,就要獲取一次,若是不可重入,那麼就跪了.git

3 . 如何實現可重入鎖

爲每一個鎖關聯一個獲取計數器和一個全部者線程,當計數值爲0的時候,這個所就沒有被任何線程只有.當線程請求一個未被持有的鎖時,JVM將記下鎖的持有者,而且將獲取計數值置爲1,若是同一個線程再次獲取這個鎖,技術值將遞增,退出一次同步代碼塊,計算值遞減,當計數值爲0時,這個鎖就被釋放.
ReentrantLock裏面有實現github

4 . 有不可重入鎖嗎

這個還真有.Linux下的pthread_mutex_t鎖是默認是非遞歸的。能夠經過設置PTHREAD_MUTEX_RECURSIVE屬性,將pthread_mutex_t鎖設置爲遞歸鎖。若是要本身實現不可重入鎖,同可重入鎖,這個計數器只能爲1.或者0,再次進入的時候,發現已是1了,就進行阻塞.jdk裏面沒有默認的實現類.編程

5 . demo代碼展現

5.1 內置鎖的可重入併發

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
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對象的可重入ide

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
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();
    }
}

 

5.3 不一樣線程不可訪問同一鎖post

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
import java.util.concurrent.locks.Lock;
import java.util.concurrent.locks.ReentrantLock;

public class ReentrantTwoThreadTest {
    private static Lock lock = new ReentrantLock();

    private static class T1 extends Thread {
        @Override
        public void run() {
            System.out.println("線程1啓動");
            lock.lock();
            try {
                Thread.sleep(10000);
            } catch (InterruptedException e) {
                e.printStackTrace();
            } finally {
                lock.unlock();
            }
            System.out.println("線程2終止");
        }
    }

    private static class T2 extends Thread {
        @Override
        public void run() {
            System.out.println("線程2啓動");
            lock.lock();
            lock.unlock();
            System.out.println("線程2終止");
        }
    }


    public static void main(String[] args) {
        new T1().start();
		Thread.sleep(100);
        new T2().start();
    }
}

6. 參考文章

  1. 可重入鎖測試
  2. 生產者消費者的一個更真實的例子
  3. 淺談Java中的鎖
  4. java併發編程實戰
相關文章
相關標籤/搜索