Sync
源碼解析額,公平和非公平模式的加鎖、解鎖過程及源碼分析ReentrantLock
提供的一些其餘方法Condition
:這裏只是一提,不會有什麼有意義的內容ReentrantLock
所有源碼理解:我的閱讀ReentrantLock
源碼的時候作的註釋,須要結合AQS
一塊理解AQS
維護。在代碼的英文註釋中寫道wait queue,所以我在這裏翻譯成同步等待隊列AQS.Condition
維護,在代碼的英文註釋中也是寫道wait queue
,所以我在這裏翻譯成條件等待隊列AQS
這個類,而且大量的方法都在AQS
中實現,本文對會對使用到的方法進行解釋,可是對於AQS
內部的屬性沒有過多解釋,後續篇章寫AQS
會專門寫,建議能夠了解一下,有助於理解AQS
中的Node
類,有助於閱讀,本文不會說明在多線程編程中,同步和互斥是一個很是重要的問題。
在java中能夠經過使用synchronized
來實現共享資源的獨佔,
除此以外還可使用Lock
提供的方法來實現對共享資源的獨佔。
並且Lock
對比synchronized
具備更高的靈活性。java
ReentrantLock
是Lock
接口的一種實現,它提供了公平和非公平兩種鎖的公平機制供開發者選擇,
而且實現了鎖的可重入性(指的是對同一臨界資源重複加鎖,注意:加鎖多少次就必定要解鎖多少次)。node
ReentrantLock
提供了公平鎖和非公平鎖兩個版本供開發者選擇:編程
公平鎖:全部請求獲取鎖的線程按照前後順序排隊獲取鎖,下一個獲取鎖的線程必定是等候獲取鎖時間最長的線程,所得獲取知足FIFO
特色。安全
非公平鎖:請求獲取鎖的線程不必定須要排隊,只要鎖沒有被獲取,不管是否有線程在等待獲取所,他就能夠進行加鎖操做。eg:全部在隊列中等待鎖的線程都沒有被操做系統調度到而且鎖沒有被獲取,此時正在指定的線程須要獲取鎖就能夠直接嘗試獲取鎖多線程
公平鎖 | 非公平鎖 | |
---|---|---|
優勢 | 全部的線程均可以獲取到資源不會餓死在隊列當中 | 能夠減小CPU喚醒線程的開銷,總體的吞吐效率會高點,CPU也沒必要取喚醒全部線程,會減小喚起線程的數量 |
缺點 | 吞吐量會降低不少,隊列裏面除了第一個線程,其餘的線程都會阻塞,cpu喚醒阻塞線程的開銷會很大 | 可能致使隊列中間的線程一直獲取不到鎖或者長時間獲取不到鎖,致使餓死 |
Sync
公平與非公平的實現主要靠鎖的同步器來實現,他們都是內部抽象類Sync
的子類(姑且稱之爲抽象同步器)。app
\(\color{#FF3030}{Sync及父類AQS提供了整個加鎖和解鎖的過程及排隊等待的過程,}\)並暴露出抽象方法lock()
供實現不一樣的鎖公平機制。less
ReentrantLock
中Sync
的子類NonfairSync
提供非公平鎖同步機制,FairSync
提供公平的鎖同步機制。ide
代碼的解釋請看註釋oop
/** * Base of synchronization control for this lock. Subclassed * into fair and nonfair versions below. Uses AQS state to * represent the number of holds on the lock. */ //提供了這個鎖的同步器的基礎方法,子類NonfairSync和FairSync提供了公平和非公平兩種同步器的實現 //使用AQS的state來標識鎖的狀態 abstract static class Sync extends AbstractQueuedSynchronizer { private static final long serialVersionUID = -5179523762034025860L; /** * Performs {@link Lock#lock}. The main reason for subclassing * is to allow fast path for nonfair version. */ //抽象方法加鎖,加鎖過程交給子類實現以提供不一樣的公平機制 abstract void lock(); /** * Performs non-fair tryLock. tryAcquire is implemented in * subclasses, but both need nonfair try for trylock method. */ //默認提供了非公平機制的加鎖過程 //acquires 申請加鎖的次數,通常狀況下是一次,可是有屢次的狀況,在Condition中會看到 final boolean nonfairTryAcquire(int acquires) { final Thread current = Thread.currentThread(); //獲取鎖的狀態,getState在AQS中實現 int c = getState(); //鎖空閒 if (c == 0) { //加鎖,加鎖成功設置鎖的屬於哪一個線程信息 if (compareAndSetState(0, acquires)) { setExclusiveOwnerThread(current); return true; } } //當前線程已經成功獲取了鎖,這塊也是鎖的可重入性的體現 else if (current == getExclusiveOwnerThread()) { //將鎖的持有次數加給定的次數便可 int nextc = c + acquires; if (nextc < 0) // overflow throw new Error("Maximum lock count exceeded"); //設置加鎖次數 setState(nextc); return true; } return false; } //釋放鎖的過程 //releases釋放鎖的次數,通常狀況下是一次,可是有屢次的狀況,在Condition中會看到 protected final boolean tryRelease(int releases) { //getState在AQS中實現 int c = getState() - releases; //獨佔鎖釋放鎖的時候誰獲取的鎖誰用完釋放,期間不準其餘線程使用 /若是鎖的擁有者不是當前線程代碼結構則出了問題 if (Thread.currentThread() != getExclusiveOwnerThread()) throw new IllegalMonitorStateException(); //因爲可重入性,只有在釋放releases次後鎖狀態爲0才徹底釋放鎖,鎖纔不被佔有 boolean free = false; //若是釋放鎖後鎖狀態爲0,則表示當前線程再也不持有這個鎖 //則將持有鎖的線程exclusiveOwnerThread置null if (c == 0) { free = true; setExclusiveOwnerThread(null); } //設置鎖狀態,,在AQS中實現 setState(c); return free; } //檢查當前線程是否持當前鎖 protected final boolean isHeldExclusively() { // While we must in general read state before owner, // we don't need to do so to check if current thread is owner return getExclusiveOwnerThread() == Thread.currentThread(); } //條件等待隊列 //具體實如今AQS中實現 final ConditionObject newCondition() { return new ConditionObject(); } // Methods relayed from outer class //獲取當前鎖的持有者 final Thread getOwner() { return getState() == 0 ? null : getExclusiveOwnerThread(); } //獲取當前線程持有鎖的次數 final int getHoldCount() { return isHeldExclusively() ? getState() : 0; } //檢查鎖是否被持有 final boolean isLocked() { return getState() != 0; } /** * Reconstitutes the instance from a stream (that is, deserializes it). */ private void readObject(java.io.ObjectInputStream s) throws java.io.IOException, ClassNotFoundException { s.defaultReadObject(); setState(0); // reset to unlocked state } }
公平鎖提供了一種絕對等待時間公平的機制,鎖永遠會被同步等待隊列中等待時間最長的獲取到,
這樣能夠保證每一個在等待的線程在程序不退出的狀況下均可以獲取到鎖。
可是每個請求的鎖的線程都將進入到同步等待隊列中阻塞休眠,線程的休眠和喚醒須要耗費額外的時間,會下降效率,下降吞吐量
(整個在同步等待隊列中阻塞休眠的操做不是絕對的,只有所沒有被佔有,而且同步等待隊列爲空時能夠直接獲取鎖或者遞歸調用同一個線程獲取鎖)源碼分析
/** * Sync object for fair locks */ static final class FairSync extends Sync { private static final long serialVersionUID = -3000897897090466540L; final void lock() { //調用AQS提供的請求加鎖的方法 //緊接着下一個代碼片斷解釋 acquire(1); } /** * Fair version of tryAcquire. Don't grant access unless * recursive call or no waiters or is first. */ //公平版本的tryAcquire, //第一個獲取鎖的線程和已經獲取鎖的線程遞歸調用獲取鎖不須要再排隊等待 protected final boolean tryAcquire(int acquires) { final Thread current = Thread.currentThread(); int c = getState(); if (c == 0) { //判斷同步等待隊列中是否有其餘等待獲取鎖的線程 //沒有而且鎖沒有被其餘線程持有則能夠直接獲取鎖 if (!hasQueuedPredecessors() && compareAndSetState(0, acquires)) { setExclusiveOwnerThread(current); return true; } } //若是當前線程持有鎖,則能夠鎖計數器加一讓該線程再一次獲取鎖 else if (current == getExclusiveOwnerThread()) { int nextc = c + acquires; if (nextc < 0) throw new Error("Maximum lock count exceeded"); setState(nextc); return true; } //不然當前線程在此次嘗試獲取鎖以前就沒有獲取到鎖 //同步等待隊列中有其餘線程在嘗試獲取鎖 //則獲取鎖失敗,下一步應該會被加入到同步等待隊列 return false; } }
簡單看下hasQueuedPredecessors()
方法,這裏只解釋知足公平鎖加鎖條件的狀況
/** * Queries whether any threads have been waiting to acquire longer * than the current thread. */ //這個方法是再AQS中提供的用來判斷線同步等待隊列中是否還有等待時間比當前線程等待時間更長的線程 //tail是隊列的尾節點,head是頭節點,每一個節點會表明一個線程首尾節點除外 //再tryAcquire中咱們但願它返回的時false那麼看下返回false表明那種狀況 //返回false要求 h != t && ((s = h.next) == null|| s.thread != Thread.currentThread())爲false,那麼要麼h==t就是頭尾節點是同一個,隊列爲空 //要麼(s = h.next) == null|| s.thread != Thread.currentThread()爲false, //這就要求h.next!=null 而且h.next就是當前線程,也就是說隊列中第一個等待獲取鎖的線程就是當前線程 //那麼就能夠直接加鎖; public final boolean hasQueuedPredecessors() { // The correctness of this depends on head being initialized // before tail and on head.next being accurate if the current // thread is first in queue. Node t = tail; // Read fields in reverse initialization order Node h = head; Node s; return h != t && ((s = h.next) == null || s.thread != Thread.currentThread()); }
在公平鎖的同步器中提供了lock()
方法用來進行加鎖操做,
可重入鎖進行加鎖的方法也確實是調用同步器的lock()
來實現加鎖
加鎖入口:lock()
方法;lock()
方法定義在ReentrantLock
類裏面,經過調用同步器的加鎖操做完成加鎖過程,公平機制不影響對外暴露的接口
/** * Acquires the lock. * * <p>Acquires the lock if it is not held by another thread and returns * immediately, setting the lock hold count to one. * * <p>If the current thread already holds the lock then the hold * count is incremented by one and the method returns immediately. * * <p>If the lock is held by another thread then the * current thread becomes disabled for thread scheduling * purposes and lies dormant until the lock has been acquired, * at which time the lock hold count is set to one. */ public void lock() { sync.lock(); }
官方的註釋說明了lock
操做會作那些事情:
\(\color{#00FF00}{這裏面好像沒說明公平的方式哈,只要鎖沒被獲取就馬上獲取,感受公平鎖是綠的}\)
加鎖的過程直接調用了同步器的lock()
方法在上述的同步器中lock()
調用acquire()
方法
acquire()
方法在AQS
中實現
具體解釋見註釋
/** * Acquires in exclusive mode, ignoring interrupts. Implemented * by invoking at least once {@link #tryAcquire}, * returning on success. Otherwise the thread is queued, possibly * repeatedly blocking and unblocking, invoking {@link * #tryAcquire} until success. This method can be used * to implement method {@link Lock#lock}. * * @param arg the acquire argument. This value is conveyed to * {@link #tryAcquire} but is otherwise uninterpreted and * can represent anything you like. */ //以獨佔的方法加鎖,而且忽略中斷 //那是否是還有響應中斷的加鎖呢?? public final void acquire(int arg) { //先嚐試調用同步器的tryAcquire()方法加鎖 if (!tryAcquire(arg) && //加鎖失敗的狀況下將當前線程放入同步等待隊列中 acquireQueued(addWaiter(Node.EXCLUSIVE), arg)) //acquireQueued返回值是線程在等待期間是否被中斷,若是有則還原中斷現場 selfInterrupt(); }
addWaiter()
方法,使用當前線程構造一個同步等待隊列的節點,而且放在隊尾,在AQS
中實現
/** * Creates and enqueues node for current thread and given mode. * * @param mode Node.EXCLUSIVE for exclusive, Node.SHARED for shared * @return the new node */ private Node addWaiter(Node mode) { //爲當前的線程構造一個同步等待隊列中的節點,在可重入鎖中式排他的模式(mode==Node.EXCLUSIVE) Node node = new Node(Thread.currentThread(), mode); // Try the fast path of enq; backup to full enq on failure Node pred = tail; //若是隊尾不爲空 if (pred != null) { node.prev = pred;//將當前節點放在隊尾 //使用CAS操做原子的設置隊尾節點 if (compareAndSetTail(pred, node)) { pred.next = node; return node; } } //若是對尾節點爲空或者CAS設置隊尾節點失敗調用enq方法將當前線程節點添加進隊列 enq(node); return node; }
enq()
方法:若是隊列不存在或者使用CAS操做使節點入隊失敗,則進入此方法構造隊列並將節點入隊,在AQS
中實現
/** * Inserts node into queue, initializing if necessary. See picture above. * @param node the node to insert * @return node's predecessor */ private Node enq(final Node node) { //用一個死循環將當前節點添加進隊列,若是隊列不存在則建立隊列 for (;;) { Node t = tail; //尾節點爲空則堆類不存在進行初始化隊列,建立頭節點 if (t == null) { // Must initialize //使用CAS操做建立頭節點, //爲何式CAS操做,試想剛判斷出隊列不存在須要建立頭節點, //此時線程發生線程的調度當前線程阻塞,另外一個線程作一樣的操做並建立了隊列 //當前線程再次被喚醒後繼續建立隊列,會有線程安全問題 if (compareAndSetHead(new Node())) //尾節點指向頭節點 tail = head; //隊列存在死循環的將當前線程對應的節點放入到隊列當中 } else { node.prev = t; if (compareAndSetTail(t, node)) { t.next = node; return t; } } } }
acquireQueued()
方法,對於排隊等待的線程應當使其進行阻塞,減小調度以及CPU空轉的時間,除非下一個就到了這個線程獲取鎖,在AQS
中實現
這個方法的設計上若是自身是頭節點的後繼節點,那麼有可能頭節點會很快處理完成任務釋放鎖,本身就能夠獲取到鎖,避免進行線程阻塞、喚醒操做,減小資源消耗
/** * Acquires in exclusive uninterruptible mode for thread already in * queue. Used by condition wait methods as well as acquire. * * @param node the node * @param arg the acquire argument * @return {@code true} if interrupted while waiting */ final boolean acquireQueued(final Node node, int arg) { boolean failed = true; try { //當前線程中斷的標誌位 boolean interrupted = false; for (;;) { //獲取當前節點的前驅節點 final Node p = node.predecessor(); //前驅節點是頭節點則嘗試調用同步器的tryAcquire獲取鎖 //第一次進入者方法時嘗試一次獲取鎖,獲取失敗則會進行判斷是否須要進行阻塞 //若是須要阻塞則阻塞,若是不須要阻塞則會將前驅節點的waitStatus設置爲SIGNAL, //再次循環獲取鎖失敗,再次進入判斷是否須要阻塞時必定會被阻塞 //獲取失敗即使先驅節點是頭節點也會被阻塞 if (p == head && tryAcquire(arg)) { //成功獲取鎖則將當前節點設置爲頭節點 setHead(node); //原先區節點的下一個節點置空, p.next = null; // help GC //怎麼help我的理解當當前節點稱爲頭節點再被釋放的時候,那麼當前節點能夠作到不可達,從而gc failed = false; //返回線程在隊列中等待期間是否被中斷 return interrupted; } //在先驅節點不是頭結點的狀況下阻塞當前線程並使其睡眠 //直到被其餘線程喚醒,這樣能夠減小CPU的空轉,提升效率 //從阻塞喚醒後繼續for循環直到獲取到鎖, if (shouldParkAfterFailedAcquire(p, node) && //阻塞當前線程直到有其餘線程喚醒,並返回中斷信息 parkAndCheckInterrupt()) //若是在線程阻塞休眠期間線程被中斷則設置終端標記位, interrupted = true; } } finally { //若是沒有獲取到鎖(獲取鎖的過程出了意外),或者取消了獲取鎖,則取消當前線程獲取鎖的操做 if (failed) cancelAcquire(node); } }
shouldParkAfterFailedAcquire()
方法,在AQS
中實現
/** * Checks and updates status for a node that failed to acquire. * Returns true if thread should block. This is the main signal * control in all acquire loops. Requires that pred == node.prev. * * @param pred node's predecessor holding status * @param node the node * @return {@code true} if thread should block */ private static boolean shouldParkAfterFailedAcquire(Node pred, Node node) { //獲取先驅節點的等待狀態 int ws = pred.waitStatus; //SIGNAL前驅節點準備好喚醒後繼節點,後繼節點能夠安全的阻塞 if (ws == Node.SIGNAL) /* * This node has already set status asking a release * to signal it, so it can safely park. */ return true; //大於0表示先驅節點已經被取消獲取鎖及排隊 if (ws > 0) { /* * Predecessor was cancelled. Skip over predecessors and * indicate retry. */ //循環向前找到一個沒有取消的節點 do { node.prev = pred = pred.prev; } while (pred.waitStatus > 0); //更新先驅節點 pred.next = node; } else { /* * waitStatus must be 0 or PROPAGATE. Indicate that we * need a signal, but don't park yet. Caller will need to * retry to make sure it cannot acquire before parking. */ //// 更新pred結點waitStatus爲SIGNAL compareAndSetWaitStatus(pred, ws, Node.SIGNAL); } return false; }
parkAndCheckInterrupt()
方法,調用LockSupport.park()
阻塞指定線程,在AQS
中實現
/** * Convenience method to park and then check if interrupted * * @return {@code true} if interrupted */ private final boolean parkAndCheckInterrupt() { //阻塞當前線程,直到其餘線程調用LockSupport.unpark(當前線程), //使得調用unpark的線程釋放鎖後當前線程被喚醒並返回在阻塞期間線程是否被中斷 LockSupport.park(this); return Thread.interrupted(); }
cancelAcquire()
方法,取消獲取鎖,在AQS
中實現
/** * Cancels an ongoing attempt to acquire. * * @param node the node */ private void cancelAcquire(Node node) { // Ignore if node doesn't exist if (node == null) return; //節點的線程置null node.thread = null; // Skip cancelled predecessors Node pred = node.prev; //若是前驅節點已經取消,那麼循環向前找到一個沒有取消的節點並設置當前節點的前驅節點 while (pred.waitStatus > 0) node.prev = pred = pred.prev; // predNext is the apparent node to unsplice. CASes below will // fail if not, in which case, we lost race vs another cancel // or signal, so no further action is necessary. Node predNext = pred.next; // Can use unconditional write instead of CAS here. // After this atomic step, other Nodes can skip past us. // Before, we are free of interference from other threads. //設置當前節點狀態爲已經取消獲取鎖 node.waitStatus = Node.CANCELLED; // If we are the tail, remove ourselves. //若是節點自身時隊尾,則移除節點並使用CAS操做設置隊尾 if (node == tail && compareAndSetTail(node, pred)) { compareAndSetNext(pred, predNext, null); } else { // If successor needs signal, try to set pred's next-link // so it will get one. Otherwise wake it up to propagate. int ws; //前驅節點不是頭節點,則當前節點就須要阻塞 //前驅節點線程不爲null,則保證存在前驅節點 //前驅節點沒有被取消,waitStatus能夠被設置爲SIGNAL保證能夠喚醒後繼節點 if (pred != head && ((ws = pred.waitStatus) == Node.SIGNAL || (ws <= 0 && compareAndSetWaitStatus(pred, ws, Node.SIGNAL))) && pred.thread != null) { Node next = node.next; //寫一個節點存在而且沒有被取消,則CAS的將前驅節點的後繼節點設置爲當前節點的後繼節點 if (next != null && next.waitStatus <= 0) compareAndSetNext(pred, predNext, next); } else { //不然喚醒後繼線程 unparkSuccessor(node); } node.next = node; // help GC } }
至此,公平鎖的加鎖操做所有結束(或者已經取消獲取鎖),在同步等待隊列中等待的線程,若是對應的節點的先驅節點不是頭節點,則線程會被阻塞減小調度。
公平鎖的公平的保證時靠加鎖時判斷當前鎖對應的同步等待隊列中存在等待的隊列,若是有則當前線程入隊,排隊來保證的;
若是當前鎖沒有被獲取,而且隊列不存在或者隊列中沒有等待的線程則能夠直接加鎖。回到acquire()
方法,若是在線程等等待的過程當中發生了中斷,
那麼獲取到所以後會還原中斷。
經過加鎖的過程能夠發現,鎖被獲取的次數經過給state
字段增長和設置鎖所屬的線程exclusiveOwnerThread
來完成加鎖操做,
那麼當線程須要解鎖的時候應該也是對這兩個字段的操做,且解鎖必定在加鎖以後,所以不存在進入同步等待隊列等待的過程。
解鎖入口:unlock()
方法;unlock()
方法定義在ReentrantLock
類裏面,經過調用同步器的解鎖操做完成解鎖過程,公平機制不影響對外暴露的接口
代碼具體解釋見註釋
/** * Attempts to release this lock. * * <p>If the current thread is the holder of this lock then the hold * count is decremented. If the hold count is now zero then the lock * is released. If the current thread is not the holder of this * lock then {@link IllegalMonitorStateException} is thrown. * * @throws IllegalMonitorStateException if the current thread does not * hold this lock */ //嘗試釋放獲取的鎖,調用到release方法,這個方法在AQS中實現 public void unlock() { sync.release(1); }
release()
方法,在AQS
中實現
/** * Releases in exclusive mode. Implemented by unblocking one or * more threads if {@link #tryRelease} returns true. * This method can be used to implement method {@link Lock#unlock}. * * @param arg the release argument. This value is conveyed to * {@link #tryRelease} but is otherwise uninterpreted and * can represent anything you like. * @return the value returned from {@link #tryRelease} */ //釋放持有的排他鎖 public final boolean release(int arg) { //調用tryRelease()來釋放鎖,由同步器實現 //tryRelease方法的解釋在同步器章節 //若是有線程在同步等待隊列中等待獲取鎖, //那麼還應該喚醒等待的線程 if (tryRelease(arg)) { //若是存在同步等待隊列,那麼當前節點解鎖成功後回將自身節點設置爲頭節點 //所以這裏的頭節點就是自身當前線程的節點 //可是在加鎖成功的時候會將節點的thread字段設置爲null,所以沒法比對判斷 Node h = head; //後繼線程在阻塞前之前會將前驅結點的waitStatus設置爲SIGNAL=-1,所以不爲0即須要喚醒後繼節點 //爲何是不爲0,而不是等於-1??由於node有1,-1,-2,-3和0五種狀況 //0表明默認狀態,node節點剛被建立, //1表明當前節點已經取消獲取鎖, //-1表明有後繼節點須要喚醒 //-2表明節點在條件等待隊列中等待,也就是不會出如今同步等待隊列 //-3表明共享模式, //若是在獲取到鎖而且已經存在後繼節點的時候取消獲取鎖,那麼節點就會使1, //直接點線程被喚醒完成加鎖操做後釋放鎖,他的waitStatus使1而不是-1,所以使用的是waitStatus != 0 if (h != null && h.waitStatus != 0) //喚醒後繼節點 unparkSuccessor(h); return true; } return false; }
unparkSuccessor()
方法喚醒後繼節點,在AQS
中實現
/** * Wakes up node's successor, if one exists. * * @param node the node */ //喚醒頭結點的後繼節點 private void unparkSuccessor(Node node) { /* * If status is negative (i.e., possibly needing signal) try * to clear in anticipation of signalling. It is OK if this * fails or if status is changed by waiting thread. */ int ws = node.waitStatus; //頭節點的狀態<0,則在發出喚醒信號以前嘗試清除這個狀態,即將頭節點的狀態設置爲0, //容許失敗或者被等待的線程改變 if (ws < 0) compareAndSetWaitStatus(node, ws, 0); /* * Thread to unpark is held in successor, which is normally * just the next node. But if cancelled or apparently null, * traverse backwards from tail to find the actual * non-cancelled successor. */ Node s = node.next; //下一個節點不存在或者取消了獲取鎖,則沿着隊列從後往前找到第一個沒有取消的節點 if (s == null || s.waitStatus > 0) { s = null; for (Node t = tail; t != null && t != node; t = t.prev) if (t.waitStatus <= 0) s = t; } //喚醒沒有取消獲取鎖的第一個節點 if (s != null) LockSupport.unpark(s.thread); }
至此可重入鎖的公平模式的加鎖和解鎖所有結束
問題:在解鎖的最後一步調用了LockSupport.unpark()
來解鎖,
而一個線程B
進入同步等待隊列阻塞的時候根據先去接點的waitState==-1
來判斷是否須要阻塞,
那麼在他判斷完前驅節點線程A
waitState==-1
成立而後發生系統調度,執行其餘線程,
而這時候線程A
獲取鎖並解鎖調用了LockSupport.unpark()
,而後執行線程B
,
線程B
會執行阻塞的過程,線程B
會被阻塞掉,而後後面的節點都不能獲取鎖麼?
除了公平的加鎖方式,可重入鎖還提供了非公平模式(默認)的加鎖。在非公平模式下只要鎖尚未被其餘線程獲取,就有機會成功獲取鎖,
固然已加入到隊列中的線程仍是要按照順序排隊獲取。這樣作會減小須要阻塞、喚醒的線程,下降因爲阻塞、喚醒帶來的額外開銷,
可是在隊列中等待的線程可能會被活活餓死(很慘的那種,出了問題排查的時候)
/** * Sync object for non-fair locks */ static final class NonfairSync extends Sync { private static final long serialVersionUID = 7316153563782823691L; /** * Performs lock. Try immediate barge, backing up to normal * acquire on failure. */ final void lock() { //和公平鎖最大的區別 //若是當前鎖沒有被其餘線程獲取則直接嘗試加鎖 //沒有被其餘線程獲取體如今參數值是0 if (compareAndSetState(0, 1)) setExclusiveOwnerThread(Thread.currentThread()); else //調用AQS的acquire方法請求加鎖,和公平鎖一致 acquire(1); } protected final boolean tryAcquire(int acquires) { //調用父類Sync的nonfairTryAcquire請求加鎖 return nonfairTryAcquire(acquires); } }
加鎖入口同公平模式:
public void lock() { //都是調用到同步器的lock方法 sync.lock(); }
lock()
直接調用同步器實現的lock()
/** * Performs lock. Try immediate barge, backing up to normal * acquire on failure. */ final void lock() { //在這裏無論是否有線程在排隊,直接嘗試加鎖 if (compareAndSetState(0, 1)) setExclusiveOwnerThread(Thread.currentThread()); else //加鎖失敗則調用AQS的acquire方法 acquire(1); }
acquire()
方法在AQS
中實現,和公平鎖的一致,方便閱讀就再寫一次
具體解釋見註釋
//以獨佔的方法加鎖,而且忽略中斷 //那是否是還有響應中斷的加鎖呢?? public final void acquire(int arg) { //先嚐試調用同步器的tryAcquire()方法加鎖 if (!tryAcquire(arg) && //加鎖失敗的狀況下將當前線程放入同步等待隊列中 acquireQueued(addWaiter(Node.EXCLUSIVE), arg)) //acquireQueued返回值是線程在等待期間是否被中斷,若是有則還原中斷現場 selfInterrupt(); }
同步器的tryAcquire()
方法見非公平模式的同步器,會調用到Sync
的nonfairTryAcquire()
方法,
若是加鎖失敗則會依次構建同步等待隊列->嘗試加鎖->失敗則判斷是否須要進行阻塞->是則阻塞等待前驅節點喚醒->嘗試加鎖這樣的流程
這個流程同公平鎖
//默認提供了非公平機制的加鎖過程 //acquires 申請加鎖的次數,通常狀況下是一次,可是有屢次的狀況,在Condition中會看到 final boolean nonfairTryAcquire(int acquires) { final Thread current = Thread.currentThread(); //獲取鎖的狀態,getState在AQS中實現 int c = getState(); //鎖空閒 if (c == 0) { //加鎖,加鎖成功設置鎖的屬於哪一個線程信息 if (compareAndSetState(0, acquires)) { setExclusiveOwnerThread(current); return true; } } //當前線程已經成功獲取了鎖,這塊也是鎖的可重入性的體現 else if (current == getExclusiveOwnerThread()) { //將鎖的持有次數加給定的次數便可 int nextc = c + acquires; if (nextc < 0) // overflow throw new Error("Maximum lock count exceeded"); //設置加鎖次數 setState(nextc); return true; } return false; }
非公平鎖的解鎖過程同公平鎖,釋放過程不存在公平於非公平,具體邏輯所有由Sync
和AQS
實現;
方法名稱 | 返回值類型 | 方法描述 |
---|---|---|
lockInterruptibly() |
void |
以響應中斷的方式獲取鎖,若是在鎖獲取以前發生中斷直接拋出中斷異常,在從同步等待隊列中被喚醒後檢查在等待期間是否有中斷髮生,若是有則拋出中斷異常 |
tryLock() |
boolean |
嘗試一次以非公平模式獲取鎖,當且僅當鎖沒有被獲取時有可能獲取成功,即使鎖私用的是公平模式,直接調用 Sync 的非公平模式獲取一次鎖,返回獲取結果 |
tryLock(long timeout, TimeUnit unit) |
boolean |
含有超時等待功能的獲取鎖,若是線程進入同步等待隊列阻塞,則只會阻塞指定的時間,這個功能由LockSupport 類提供 |
newCondition() |
Condition |
獲取一個Condition 對象,能夠提供相似Object Moitor 同樣的功能 |
getHoldCount() |
int |
獲取持有鎖的次數,通常用於測試鎖 |
isHeldByCurrentThread |
boolean |
檢查當前線程是否持有這個鎖 |
isLocked |
boolean |
檢查鎖是否被任何一個線程獲取 |
isFair() |
boolean |
檢查當前鎖是不是公平鎖 |
getOwner() |
Thread |
獲取持有鎖的線程 |
hasQueuedThreads() |
boolean |
同步等待隊列是否有線程等待獲取鎖 |
hasQueuedThread(Thread thread) |
boolean |
判斷指定線程是否在同步等待隊列中等待 |
getQueueLength() |
int |
獲取同步等待對列的長度,隊列中的線程不必定都是等待獲取鎖的線程,還有可能已經取消 |
hasWaiters(Condition condition) |
boolean |
判斷給定的condition 中是否由線程等待 |
getWaitQueueLength(Condition condition) |
int |
獲取給定condition 中等待隊列的長度 |
getWaitingThreads(Condition condition) |
Collection<Thread> |
獲取給定的condition 中全部的等待線程 |
在ReentrantLock
中提供了一個newCondition()
方法,
利用返回的Condition
對象能夠實現Object.wait()、Object.notify()、Object.notifyAll()
等功能,而且具備更強大的功能。
返回的Condition
的實現是在AQS
當中實現,因此這個放在AQS
學習完了寫。
\(\color{#FF3030}{轉載請標明出處}\)
/** * 一個能夠重入的排他鎖基本的行爲和語義與使用synchronized做爲 * 隱式的鎖的監聽器是同樣的,可是實現了更多的功能 * * 一個可重入鎖後被最後一次成功加鎖可是沒有解鎖的線程持有 * 當一個鎖沒有被不被任何一個線程持有,這是一個線程來申請這個鎖將會被申請成功 * 可使用{@link #isHeldByCurrentThread}, 和 {@link * #getHoldCount}檢查當前線程是否持有鎖 * * 這個類的構造器提供了一個fairness參數來設定是否公平 * <當設置爲true時,是個公平鎖,鎖老是被當前等待時間最長的線程獲取 * 不然不能保證將按照何種順序獲取該鎖 * 使用公平鎖的程序吞吐量比默認(非公平鎖)更小 * 可是在得到此線程和保證保證不被餓死方面會比默認更好 * 然而鎖的g公平性並不保證線程的公平性。所以使用公平鎖的 * 所以使用公平鎖的的多個線程可能有一個會屢次得到他,而其餘線程可能一次也沒有 * * 注意:隨機的tryLock並不支持公平性, * 只要鎖可用即便有其餘線程正在等待也能夠獲取他 * * 在使用lock後使用try語句而且將unlock放在finally中 * * 除了實現{@link Lock}接口外, * 還有這個類定義了許多檢查鎖狀態的方法。 * 其中的一些方法方法只對檢測和監視有用 * * <p>Serialization of this class behaves in the same way as built-in * locks: a deserialized lock is in the unlocked state, regardless of * its state when serialized. * * <p>這個鎖最多支持衝入2147483647 次(遞歸調用) * */ public class ReentrantLock implements Lock, java.io.Serializable { private static final long serialVersionUID = 7373984872572414699L; /** Synchronizer providing all implementation mechanics */ private final Sync sync; /** * Base of synchronization control for this lock. Subclassed * into fair and nonfair versions below. Uses AQS state to * represent the number of holds on the lock. */ abstract static class Sync extends AbstractQueuedSynchronizer { private static final long serialVersionUID = -5179523762034025860L; /** * Performs {@link Lock#lock}. The main reason for subclassing * is to allow fast path for nonfair version. */ abstract void lock(); /** * Performs non-fair tryLock. tryAcquire is implemented in * subclasses, but both need nonfair try for trylock method. */ final boolean nonfairTryAcquire(int acquires) { final Thread current = Thread.currentThread(); int c = getState(); if (c == 0) { if (compareAndSetState(0, acquires)) { setExclusiveOwnerThread(current); return true; } } else if (current == getExclusiveOwnerThread()) { int nextc = c + acquires; if (nextc < 0) // overflow throw new Error("Maximum lock count exceeded"); setState(nextc); return true; } return false; } protected final boolean tryRelease(int releases) { int c = getState() - releases; if (Thread.currentThread() != getExclusiveOwnerThread()) throw new IllegalMonitorStateException(); boolean free = false; if (c == 0) { free = true; setExclusiveOwnerThread(null); } setState(c); return free; } protected final boolean isHeldExclusively() { // While we must in general read state before owner, // we don't need to do so to check if current thread is owner return getExclusiveOwnerThread() == Thread.currentThread(); } final ConditionObject newCondition() { return new ConditionObject(); } // Methods relayed from outer class final Thread getOwner() { return getState() == 0 ? null : getExclusiveOwnerThread(); } final int getHoldCount() { return isHeldExclusively() ? getState() : 0; } final boolean isLocked() { return getState() != 0; } /** * Reconstitutes the instance from a stream (that is, deserializes it). */ private void readObject(java.io.ObjectInputStream s) throws java.io.IOException, ClassNotFoundException { s.defaultReadObject(); setState(0); // reset to unlocked state } } /** * 可重入鎖非公平同步器 */ static final class NonfairSync extends Sync { private static final long serialVersionUID = 7316153563782823691L; /** * 加鎖. Try immediate barge, backing up to normal * acquire on failure. */ final void lock() { //使用cas操做加鎖,成功的話將鎖的擁有線程置爲本身 if (compareAndSetState(0, 1)) setExclusiveOwnerThread(Thread.currentThread()); else //排他模式獲取,忽略中斷,經過再次調用tryAcquire獲取鎖, //獲取失敗將進入等待隊列,可能會重複的阻塞和取消阻塞, //直到調用tryAcquire獲取鎖成功 acquire(1); } //實現AQS的tryAcquire()方法(該方法進行一次嘗試獲取鎖) protected final boolean tryAcquire(int acquires) { return nonfairTryAcquire(acquires); } } /** * 可重入鎖的公平同步器 */ static final class FairSync extends Sync { private static final long serialVersionUID = -3000897897090466540L; //公平模式與非公平模式的區別,公平模式下全部的所獲取都會檢查當前的等待隊列 //非公平鎖能夠進行搶佔,即使有等待隊列中有等待的線程,只要鎖對象沒有加鎖成功,既能夠被加鎖 final void lock() { acquire(1); } /** * 實現AQS的tryAcquire方法,加鎖時會檢查當前鎖的等待隊列的實際元素 * 當等待隊列爲空(頭節點==尾節點)或者頭結點的下一個節點對應的線程試當前的線程能夠加鎖成功 * 若是當前線程已經持有 */ protected final boolean tryAcquire(int acquires) { final Thread current = Thread.currentThread(); int c = getState(); if (c == 0) { if (!hasQueuedPredecessors() && compareAndSetState(0, acquires)) { setExclusiveOwnerThread(current); return true; } } else if (current == getExclusiveOwnerThread()) { int nextc = c + acquires; if (nextc < 0) throw new Error("Maximum lock count exceeded"); setState(nextc); return true; } return false; } } /** * 建立一個可重入鎖.非公平模式 * 與使用 {@code ReentrantLock(false)}.建立效果同樣 */ public ReentrantLock() { sync = new NonfairSync(); } /** * 建立給定模式(公平或者非公平)的可重入鎖 * @param fair {@codetrue} 使用公平模式 */ public ReentrantLock(boolean fair) { sync = fair ? new FairSync() : new NonfairSync(); } /** * 獲取鎖. * * <p>若是這個鎖沒有被其餘線程持有,則獲取鎖並馬上返回, * 將鎖的計數器記爲1 * * 若是當前線程已經持有鎖,則將鎖的計數器自增1, * 而且馬上返回 * * <p>若是鎖被其餘線程持有 * 那麼當前線程將會由於線程調度緣由設置禁用而且爲休眠狀態, * 而且在鎖被獲取以前處於休眠狀態 * at which time the lock hold count is set to one. */ public void lock() { sync.lock(); } /** * 獲取鎖直到當前線程被阻塞 * * <p>若是鎖沒被其餘的線程獲取則獲取鎖並返回 * * 若是鎖已經被當前線程獲取,則將鎖的計數器自增 * * 若是鎖被其餘線程持有 * 處於線程調度的目的會將當前線程設置爲禁用而且爲休眠狀態 * 直到如下兩種狀況中的一種發生: * * <ul> * * <li>當前線程獲取到鎖; or * * <li>其餘的線程中斷了當前的線程 * * </ul> * * <p>若是當前線程獲取到了鎖,那麼將鎖的計數器設置爲1 * * <p>若是當前線程 * * 在進入這個方法的時候中斷狀態已經被設置; * 或者在獲取鎖的過程當中被中斷 * * InterruptedException異常將會被拋出而且清除中斷標記位 * * @throws InterruptedException if the current thread is interrupted */ public void lockInterruptibly() throws InterruptedException { //該方法會先檢查當前線程是否被中斷,而後調用tryAcquire獲取鎖 //獲取失敗則調用doAcquireInterruptibly //這個方法和忽略中斷的加鎖acquireQueue基本相同,不一樣點是 //當線程在調用LockSupport.park(this)被喚醒後,Lock方法會忽略是否該線程被中斷, //若被中斷該方法會拋出線程中斷異常 sync.acquireInterruptibly(1); } /** * 當且僅當鎖沒被其餘線程獲取時才獲取鎖 * * <p>當且僅當鎖沒被其餘線程獲取時獲取鎖而且返回ture,設置鎖的計數器爲1 * 即便這個鎖被設定爲公平鎖,只要沒有其餘線程獲取到鎖,使用tryLock也能馬上獲取到鎖 * 不管是否有其餘線程在排隊 * 即便這種行爲破壞了公平,但在某些狀況下是有用的 * 若是想要這個鎖的公平設置可使用 * {@link #tryLock(long, TimeUnit) tryLock(0, TimeUnit.SECONDS) } * 這二者幾乎是的等價的 (依然會檢測中斷). * * 若是當前線程已經持有鎖,那麼將鎖計數器自增長一 * * 若是當前鎖被其餘線程持有,那麼返回false * * @return {@code true} if the lock was free and was acquired by the * current thread, or the lock was already held by the current * thread; and {@code false} otherwise */ public boolean tryLock() { //與非公平鎖tryAcquire方法內容相同 return sync.nonfairTryAcquire(1); } /** * 在超時等待的時間內獲取到鎖而且線程沒有被中斷 * * 若是在超時等待的時間內獲取到鎖而且沒有被中斷,鎖沒有被其餘線程持有 * 將返回true,同時將鎖計數器設置爲1 * 若是當前鎖使用的是公平鎖的模式 * 有其餘的線程在等待這個鎖,都不能獲取到鎖這個功能由(tryAcquire實現) * 若是想要在超時等待的時間內破壞鎖的公平性獲取鎖能夠和TryLock聯合使用 * * <pre> {@code * if (lock.tryLock() || * lock.tryLock(timeout, unit)) { * ... * }}</pre> * * <p>若是當前的線程已經擁有鎖那麼將鎖計數器自增長一(tryAcquire實現) * * <p>若是鎖被其餘線程持有那麼處於線程調度的目的會將當前線程置爲不可用 * 而且睡眠直到下面一種事情發生: * * <ul> * * <li>鎖被當前線程獲取,或者 * * <li>其餘線程中斷了當前線程 * * <li>時間超過了設置的等待時間 * * </ul> * * <p>若是獲取到了鎖將返回ture,而且將鎖計數器設置爲1 * * <p>若是當前線程 * * <ul> * * <li>在進入這個方法以前,中斷標記位被設置 * * 或者獲取鎖的時候被中斷 * * </ul> * 會拋出 {@link InterruptedException} 異常,而且清楚中斷標記位 * * <p>若是超過了設置的等待時間將會返回false(其實還會嘗試獲取一次鎖) * 若是設置的超時等待時間少於等於0,這個方法不會一直等待 * * <p>這個方法會先響應中斷,而不是鎖的獲取和等待 * * @param timeout the time to wait for the lock * @param unit the time unit of the timeout argument * @return {@code true} if the lock was free and was acquired by the * current thread, or the lock was already held by the current * thread; and {@code false} if the waiting time elapsed before * the lock could be acquired * @throws InterruptedException if the current thread is interrupted * @throws NullPointerException if the time unit is null */ public boolean tryLock(long timeout, TimeUnit unit) throws InterruptedException { return sync.tryAcquireNanos(1, unit.toNanos(timeout)); } /** * 試圖釋放鎖 * * <p>若是當前線程是鎖的持有者,則鎖的計數器自減1, * 若是鎖的計數器爲0,則釋放鎖 * 若是當前線程不是鎖的持有者,將拋出異常 * 釋放鎖成功後若是等待隊列中還有等待的線程,那麼調用lockSupport.unspark喚醒等待的線程 * {@link IllegalMonitorStateException}. * * @throws IllegalMonitorStateException if the current thread does not * hold this lock */ public void unlock() { sync.release(1); } /** * Returns a {@link Condition} instance for use with this * {@link Lock} instance. * * <p>The returned {@link Condition} instance supports the same * usages as do the {@link Object} monitor methods ({@link * Object#wait() wait}, {@link Object#notify notify}, and {@link * Object#notifyAll notifyAll}) when used with the built-in * monitor lock. * * <ul> * * <li>If this lock is not held when any of the {@link Condition} * {@linkplain Condition#await() waiting} or {@linkplain * Condition#signal signalling} methods are called, then an {@link * IllegalMonitorStateException} is thrown. * * <li>When the condition {@linkplain Condition#await() waiting} * methods are called the lock is released and, before they * return, the lock is reacquired and the lock hold count restored * to what it was when the method was called. * * <li>If a thread is {@linkplain Thread#interrupt interrupted} * while waiting then the wait will terminate, an {@link * InterruptedException} will be thrown, and the thread's * interrupted status will be cleared. * * <li> Waiting threads are signalled in FIFO order. * * <li>The ordering of lock reacquisition for threads returning * from waiting methods is the same as for threads initially * acquiring the lock, which is in the default case not specified, * but for <em>fair</em> locks favors those threads that have been * waiting the longest. * * </ul> * * @return the Condition object */ public Condition newCondition() { return sync.newCondition(); } /** * 查詢鎖被當前線程加鎖的次數 * * <p>線程對於每一個加鎖的操做都有一個對應的解鎖操做 * * <p>這個操做一般只被用來測試和調試 * For example, if a certain section of code should * not be entered with the lock already held then we can assert that * fact: * * <pre> {@code * class X { * ReentrantLock lock = new ReentrantLock(); * // ... * public void m() { * assert lock.getHoldCount() == 0; * lock.lock(); * try { * // ... method body * } finally { * lock.unlock(); * } * } * }}</pre> * * @return the number of holds on this lock by the current thread, * or zero if this lock is not held by the current thread */ public int getHoldCount() { return sync.getHoldCount(); } /** * 檢查當前線程是否持有這個鎖 * * <p>Analogous to the {@link Thread#holdsLock(Object)} method for * built-in monitor locks, this method is typically used for * debugging and testing. For example, a method that should only be * called while a lock is held can assert that this is the case: * * <pre> {@code * class X { * ReentrantLock lock = new ReentrantLock(); * // ... * * public void m() { * assert lock.isHeldByCurrentThread(); * // ... method body * } * }}</pre> * * <p>It can also be used to ensure that a reentrant lock is used * in a non-reentrant manner, for example: * * <pre> {@code * class X { * ReentrantLock lock = new ReentrantLock(); * // ... * * public void m() { * assert !lock.isHeldByCurrentThread(); * lock.lock(); * try { * // ... method body * } finally { * lock.unlock(); * } * } * }}</pre> * * @return {@code true} if current thread holds this lock and * {@code false} otherwise */ public boolean isHeldByCurrentThread() { return sync.isHeldExclusively(); } /** * 檢查這個鎖是否被任意一個線程持有(檢查鎖的計數器state是不是0) * 這個方法用來監控系統狀態,而不是用來同步, * * @return {@code true} if any thread holds this lock and * {@code false} otherwise */ public boolean isLocked() { return sync.isLocked(); } /** * 測試當前鎖是公平鎖仍是非公平鎖 * * @return {@code true} if this lock has fairness set true */ public final boolean isFair() { return sync instanceof FairSync; } /** * 獲取當前擁有鎖的線程,若是沒有線程持有,則返回null * 此方法的目的是爲了方便構造提供更普遍的鎖監視設施的子類。 * * @return the owner, or {@code null} if not owned */ protected Thread getOwner() { return sync.getOwner(); } /** * 檢查是否有現成正在等待獲取此鎖(head!=tail) Note that * 由於線程取消獲取鎖可能發生在任什麼時候間,因此返回值爲true不能保證 * 必定有其餘線程在獲取此鎖,(好比等待隊列中的線程已經取消獲取此鎖) * 這個方法的設計被用來監控系統 * * @return {@code true} if there may be other threads waiting to * acquire the lock */ public final boolean hasQueuedThreads() { return sync.hasQueuedThreads(); } /** * 判斷給定的線程是否在等待這個鎖 * 線程取消獲取鎖可能發生在任什麼時候間, * true的返回值不表明這個線程還在等待獲取這個鎖 * 這個方法的設計被用來監控系統 * * @param thread the thread * @return {@code true} if the given thread is queued waiting for this lock * @throws NullPointerException if the thread is null */ public final boolean hasQueuedThread(Thread thread) { return sync.isQueued(thread); } /** * 返回等待隊列中等待獲取鎖的數量的估計值 * 這個方法返回的是一個估計值由於隊列中的線程數量可能在變化 * 這個方法的設計被用來監控系統 * * @return the estimated number of threads waiting for this lock */ public final int getQueueLength() { return sync.getQueueLength(); } /** * 返回一個線程集合,集合中的線程可能在等待獲取鎖 * 由於線程獲取鎖可能被取消因此獲取到的集合不是準確的 * 此方法的目的是爲了方便構造提供更普遍的鎖監視設施的子類 * * @return the collection of threads */ protected Collection<Thread> getQueuedThreads() { return sync.getQueuedThreads(); } /** * 查詢與這個鎖關聯的condition是否有線程正在等待,便是否有現成調用過與 * await方法.由於等待超時和線程中斷髮生在任什麼時候候 * 因此返回值true不表明未來會有信號來喚醒線程 * 這個方法的設計被用來監控系統 * * @param condition the condition * @return {@code true} if there are any waiting threads * @throws IllegalMonitorStateException if this lock is not held * @throws IllegalArgumentException if the given condition is * not associated with this lock * @throws NullPointerException if the condition is null */ public boolean hasWaiters(Condition condition) { if (condition == null) throw new NullPointerException(); if (!(condition instanceof AbstractQueuedSynchronizer.ConditionObject)) throw new IllegalArgumentException("not owner"); //經過檢查condition隊列是中的節點是否處於condition狀態實現 return sync.hasWaiters((AbstractQueuedSynchronizer.ConditionObject)condition); } /** * 返回與鎖相關的指定的condition的隊列中的線程數量,注意這是個估計值 * 由於線程等待超時和中斷髮生在任什麼時候間 * 所以隊列一直在動態的變化,可能尚未統計完就已經發生了變化. * * @param condition the condition * @return the estimated number of waiting threads * @throws IllegalMonitorStateException if this lock is not held * @throws IllegalArgumentException if the given condition is * not associated with this lock * @throws NullPointerException if the condition is null */ public int getWaitQueueLength(Condition condition) { if (condition == null) throw new NullPointerException(); if (!(condition instanceof AbstractQueuedSynchronizer.ConditionObject)) throw new IllegalArgumentException("not owner"); return sync.getWaitQueueLength((AbstractQueuedSynchronizer.ConditionObject)condition); } /** * 返回與鎖相關的指定的condition的隊列中的線程集合 * 返回的集合只是一個估計值, * 由於線程等待超時和中斷髮生在任什麼時候間 * * @param condition the condition * @return the collection of threads * @throws IllegalMonitorStateException if this lock is not held * @throws IllegalArgumentException if the given condition is * not associated with this lock * @throws NullPointerException if the condition is null */ protected Collection<Thread> getWaitingThreads(Condition condition) { if (condition == null) throw new NullPointerException(); if (!(condition instanceof AbstractQueuedSynchronizer.ConditionObject)) throw new IllegalArgumentException("not owner"); return sync.getWaitingThreads((AbstractQueuedSynchronizer.ConditionObject)condition); } /** * Returns a string identifying this lock, as well as its lock state. * The state, in brackets, includes either the String {@code "Unlocked"} * or the String {@code "Locked by"} followed by the * {@linkplain Thread#getName name} of the owning thread. * * @return a string identifying this lock, as well as its lock state */ public String toString() { Thread o = sync.getOwner(); return super.toString() + ((o == null) ? "[Unlocked]" : "[Locked by thread " + o.getName() + "]"); } }