鎖的概念就不用多解釋了,當某個線程A已經持有了一個鎖,當線程B嘗試進入被這個鎖保護的代碼段的時候.就會被阻塞.而鎖的操做粒度是」線程」,而不是調用(至於爲何要這樣,下面解釋).同一個線程再次進入同步代碼的時候.可使用本身已經獲取到的鎖,這就是可重入鎖
java裏面內置鎖(synchronize)和Lock(ReentrantLock)都是可重入的html
若是線程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
爲每一個鎖關聯一個獲取計數器和一個全部者線程,當計數值爲0的時候,這個所就沒有被任何線程只有.當線程請求一個未被持有的鎖時,JVM將記下鎖的持有者,而且將獲取計數值置爲1,若是同一個線程再次獲取這個鎖,技術值將遞增,退出一次同步代碼塊,計算值遞減,當計數值爲0時,這個鎖就被釋放.
ReentrantLock裏面有實現github
這個還真有.Linux下的pthread_mutex_t鎖是默認是非遞歸的。能夠經過設置PTHREAD_MUTEX_RECURSIVE屬性,將pthread_mutex_t鎖設置爲遞歸鎖。若是要本身實現不可重入鎖,同可重入鎖,這個計數器只能爲1.或者0,再次進入的時候,發現已是1了,就進行阻塞.jdk裏面沒有默認的實現類.編程
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(); } } |