1 回答

TA貢獻1784條經驗 獲得超9個贊
每個鎖對象都有兩個隊列,一個是就緒隊列,一個是阻塞隊列,就緒隊列存儲了將要獲得鎖的線程,阻塞隊列存儲了被阻塞的線程,當一個被線程被喚醒 (notify)后,才會進入到就緒隊列,等待獲得鎖。你說的等待隊列也就是阻塞隊列。
例如:當一開始線程a第一次執行對象account.add()方法時,JVM會檢查鎖對象account的就緒隊列是否已經有線程在等待,如果有則表明account的鎖已經被占用了,由于是第一次運行,account的就緒隊列為空,所以線程a獲得了鎖, 執行account.add方法。如果恰好在這個時候,線程b要執行account.withdraw方法,因為線程a已經獲得了鎖還沒有釋放,所以線程b要進入account的就緒隊列,等到得到鎖后才可以執行。一個線程執行臨界區代碼過程如下:
1.獲得同步鎖2.清空工作內存3.從主存拷貝變量副本到工作內存4.對這些變量計算5.將變量從工作內存寫回到主存6.釋放鎖
可見,synchronized既保證了多線程的并發有序性,又保證了多線程的內存可見性。notify 不會釋放鎖,而是通知鎖對象的阻塞隊列里的某一線程(被阻塞,即主動調用wait方法),進入就緒隊列。線程釋放鎖的方式,通常是 主動調用wait方法、同步代碼塊結束釋放鎖資源。notifyall 是 喚醒阻塞隊列里的所有阻塞線程,他們都將進入就緒隊列,而notify的數量是一個。同步代碼塊結束釋放鎖資源,對象就緒隊列中的某一線程獲得鎖資源而開始線程;如果不使用notify 那么阻塞隊列 里 線程將一直處于阻塞狀態,即使就緒隊列里 線程都執行完了,阻塞隊列 里 線程也將一直處于阻塞狀態.某一線程釋放鎖之后,將會從就緒隊列中 隨機找出?(有疑問) 一線程,使之獲得鎖資源。
添加回答
舉報