一道Java的題目:java
關於sleep()和wait(),如下描述錯誤的一項是:線程
截取網上的一段話:cdn
全部對象都自動含有單一的鎖。
JVM負責跟蹤對象被加鎖的次數。若是一個對象被解鎖,其計數變爲0。在任務(線程)第一次給對象加鎖的時候,計數變爲1。每當這個相同的任務(線程)在此對象上得到鎖時,計數會遞增。
只有首先得到鎖的任務(線程)才能再次加鎖(鎖的重入)。
每當任務離開一個synchronized(同步)方法,計數遞減,當計數爲0的時候,鎖被徹底釋放,此時別的任務就可使用此資源。對象
雖然java底層使用隊列實現的,可是用池來描述會更容易理解,後面會看到blog
在Java中,每一個對象都有兩個池,鎖(monitor)池和等待池隊列
鎖池:假設線程A已經擁有了某個對象的鎖,而其它的線程想要調用這個對象的某個synchronized方法(或者synchronized塊),因爲這些線程在進入對象的synchronized方法以前必須先得到該對象的鎖的擁有權,可是該對象的鎖目前正被線程A擁有,因此這些線程就進入了該對象的鎖池中。資源
等待池:假設一個線程A調用了某個對象的wait()方法,線程A就會釋放該對象的鎖(由於wait()方法必須出如今synchronized中,這樣天然在執行wait()方法以前線程A就已經擁有了該對象的鎖),同時線程A就進入到了該對象的等待池中。
若是另外的一個線程調用了相同對象的notifyAll()方法,那麼處於該對象的等待池中的線程就會所有進入該對象的鎖池中,準備爭奪鎖的擁有權。若是另外的一個線程調用了相同對象的notify()方法,那麼僅僅有一個處於該對象的等待池中的線程(隨機)會進入該對象的鎖池.同步
若是線程調用了對象的 wait()方法,那麼線程便會釋放鎖進入該對象的等待池中,等待池中的線程不會去競爭該對象的鎖。 當有線程調用了對象的 notifyAll()方法(喚醒全部 wait 線程)或 notify()方法(只隨機喚醒一個 wait 線程),被喚醒的的線程便會進入該對象的鎖池中,鎖池中的線程會去競爭該對象鎖。 優先級高的線程競爭到對象鎖的機率大,倘若某線程沒有競爭到該對象鎖,它還會留在鎖池中,惟有線程再次調用 wait()方法,它纔會從新回到等待池中。而競爭到對象鎖的線程則繼續往下執行,直到執行完了 synchronized 代碼塊,它會釋放掉該對象鎖,這時鎖池中的線程會繼續競爭該對象鎖。it
注:wait() ,notifyAll(),notify() 三個方法都是Object類中的方法.io
public final void wait() throws InterruptedException,IllegalMonitorStateException
該方法用來將當前線程置入休眠狀態,直到接到通知或被中斷爲止。在調用 wait()以前,線程必需要得到該對象的對象級別鎖,即只能在同步方法或同步塊中調用 wait()方法。進入 wait()方法後,當前線程釋放鎖。在從 wait()返回前,線程與其餘線程競爭從新得到鎖。若是調用 wait()時,沒有持有適當的鎖,則拋出 IllegalMonitorStateException,它是 RuntimeException 的一個子類,所以,不須要 try-catch 結構。
public final native void notify() throws IllegalMonitorStateException
該方法也要在同步方法或同步塊中調用,即在調用前,線程也必需要得到該對象的對象級別鎖,的若是調用 notify()時沒有持有適當的鎖,也會拋出 IllegalMonitorStateException。
該方法用來通知那些可能等待該對象的對象鎖的其餘線程。若是有多個線程等待,則線程規劃器任意挑選出其中一個 wait()狀態的線程來發出通知,並使它等待獲取該對象的對象鎖.
這裏有兩個注意點:
1.notify 後,當前線程不會立刻釋放該對象鎖,wait 所在的線程並不能立刻獲取該對象鎖,要等到程序退出 synchronized 代碼塊後,當前線程纔會釋放鎖,某一個wait所在的線程也才能夠獲取該對象鎖 但不驚動其餘一樣在等待池中等待被notify的線程們。
2.當第一個得到了該對象鎖的 wait 線程運行完畢之後,它會釋放掉該對象鎖,此時若是該對象沒有再次使用 notify 語句,則即使該對象已經空閒,其餘 wait 狀態等待的線程因爲沒有獲得該對象的通知,會繼續在等待池中,阻塞在 wait 狀態,直到這個對象發出一個 notify 或 notifyAll。
這裏須要注意:等待池中的線程們等待的是被 notify 或 notifyAll,暫時還不是鎖。這與下面的 notifyAll()方法執行後的狀況不一樣。
public final native void notifyAll() throws IllegalMonitorStateException
該方法與 notify ()方法的工做方式相同,重要的一點差別是:
notifyAll 使全部原來在該對象上 wait 的線程通通退出 wait 的狀態(即所有被喚醒,從等待池移動到鎖池,再也不等待 notify 或 notifyAll,但因爲此時尚未獲取到該對象鎖,所以還不能繼續往下執行),變成在鎖池中等待獲取該對象上的鎖.
一旦該對象鎖被釋放(notifyAll 線程退出調用了 notifyAll 的 synchronized 代碼塊的時候),他們就會去競爭。若是其中一個線程得到了該對象鎖,它就會繼續往下執行,在它退出 synchronized 代碼塊,釋放鎖後,其餘的已經被喚醒的線程將會繼續競爭獲取該鎖,一直進行下去,直到全部被喚醒的線程都執行完畢。
最開始的那道題答案是D,notifyAll()也能夠