每個鎖對象都有兩個隊列,一個是就緒隊列,一個是阻塞隊列,就緒隊列存儲了將要獲得鎖的線程,阻塞隊列存儲了被阻塞的線程,當一個被線程被喚醒 (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 那么阻塞隊列 里 線程將一直處於阻塞狀態,即使就緒隊列里 線程都執行完了,阻塞隊列 里 線程也將一直處於阻塞狀態
--------------某一線程釋放鎖之后,將會從就緒隊列中 隨機找出?(有疑問) 一線程,使之獲得鎖資源。