我先給出一個demo, 這樣你們就能夠根據我給的這段代碼, 邊調試邊看源碼了. 仍是那句話: 注意"My" , 我把ReentrantLock類 更名爲了 "MyReentrantLock"類 , "Lock"類 更名爲了"MyLock"類. 你們粘貼個人代碼的時候, 把相應的"My"都去掉就行了, 不然會編譯報錯哦.java
import java.util.Scanner; import java.util.concurrent.locks.Condition; import java.util.function.Supplier; public class ConditionTest { static final Scanner scanner = new Scanner(System.in); static volatile String cmd = ""; private static MyReentrantLock lock = new MyReentrantLock(true); private static Condition condition = lock.newCondition(); public static void main(String[] args) { for (String name : new String[]{"w1", "w2", "w3", "w4", "w5", "w6"}) new Thread(() -> func(() -> lock, name)).start(); new Thread(() -> signalOne(() -> lock, "s")).start(); while (scanner.hasNext()) { cmd = scanner.nextLine(); } } public static void func(Supplier<MyLock> myLockSupplier, String name) { blockUntilEquals(() -> cmd, name); myLockSupplier.get().lock(); System.out.println(name + "阻塞等待..."); try { condition.await(); } catch (InterruptedException e) { e.printStackTrace(); } System.out.println("釋放了" + name); myLockSupplier.get().unlock(); } public static void signalOne(Supplier<MyLock> myLockSupplier, String name) { while (true) { blockUntilEquals(() -> cmd, name); myLockSupplier.get().lock(); condition.signal(); System.out.println("通知喚醒了一個等待..."); myLockSupplier.get().unlock(); } } private static void blockUntilEquals(Supplier<String> cmdSupplier, final String expect) { while (!cmdSupplier.get().equals(expect)) quietSleep(1000); clearCmd(); } private static void quietSleep(int mills) { try { Thread.sleep(mills); } catch (InterruptedException e) { e.printStackTrace(); } } private static void clearCmd() { cmd = ""; } }
使用例子在下面. ui
首先輸入w1, 讓線程1執行await() . 而後輸入w2, 讓線程2執行await(). 而後輸入w3, 讓線程3執行await().線程
接下來輸入3次 s, 沒輸入一次s, 並按下回車, 就會signal通知一個await等待.3d
想用ReentrantLock的Condition, 那麼就首先要有個ReentrantLock鎖.調試
實例化一個鎖, ReentrantLock裏只有一個成員變量sync.blog
sync實例裏面有四個成員變量.隊列
分別表示:get
1. state - 鎖計數器cmd
2. exclusiveOwnerThread - 鎖的持有線程源碼
3. head - `等待隊列`的頭結點.
4. tail - 指向`等待隊列`的最後一個元素
而後我們實例化了一個Condition.
當我們輸入w1後, 第一個線程就申請了鎖, 而且申請成功.
而後就執行到了await()方法.
將線程1封裝爲Node節點, 而後waitState置爲-2. -2的含義是Condition.
await()方法內部的第一個步驟就是把當前線程(線程1)插入到了`條件隊列`中.
而後就開始釋放當前線程(線程1)的鎖了, 並且是徹底釋放, 一次就釋放掉所有重入次數哦, 也就是直接讓state等於0.
釋放完鎖了, 而後掛起線程1.
而後讓線程2進行await.( 也就是前面的demo程序中在控制檯輸入了w2.)
線程2執行await()以前固然是先獲取鎖了.
因爲此時, 鎖是空閒的. 因此線程2成功獲取到了鎖. 淡橙色的陰影部分爲變化的內容:
獲取鎖以後, 線程2就該執行await()了:
如上圖, 將線程封裝爲Node, 而後尾插到`條件隊裏`中, 只是await() 方法的第一步.
而後的操做, 就是徹底釋放線程2的鎖, 而後掛起線程.
若是這個時候我們在上面demo程序的控制檯輸入"s", 那麼就會讓線程s 申請鎖, 申請成功後, 就會執行signal.
首先是線程s申請鎖成功:
線程s成功獲取了鎖之後, 就是該執行signal()了.
首先將`條件隊列`裏的第一個節點脫離出來:
而後把waitState從-2改成0 :
隨後要作的就是把從`條件隊列`中脫離出來的Node(就是線程1對應的Node節點), 尾插到`等待隊列`中.
可是`等待隊列`此時還未被初始化, 因此插入到`等待隊列`以前, 要把`等待隊列`初始化了. 見下圖:
`等待隊列`初始化完了. 接下來就是把線程1對應的Node, 尾插到`等待隊列`中了:
而後將當前尾插的那個節點的前驅的waitState置爲-1. -1表示下一個節點等待着被喚醒.
接下來就是線程s會執行到unlock(). 而後就會釋放鎖, 以後就是喚醒`等待隊列`中的第一個線程.
如此就介紹完了signal()
一個signal命令, 就把一個await的線程從`條件隊列中`移到了`等待隊列`中. 到了等待隊列中以後, 剩下的就是跟"鎖解鎖後, 喚醒下一個執行"這樣的步驟同樣了.
我以爲await方法就是將線程尾插到`條件隊列`中. signal()方法就是把條件隊列中的第一個元素, 尾插入到`等待隊列`中.
因此我以爲沒必要往下分析了.
也多是我理所固然了, 有問題的話以後再補充.