educoder 使用线程锁(lock)实现线程同步_线程间的通信(一)
這篇文章主要從4個角度來講多線程間的通信:
等待/通知機制的實現:
(1)wait()方法屬于Object類,作用是讓當前執行代碼的線程進行等待,該方法用來將當前線程置于"預執行隊列"中,并且在wait()所在的代碼行處停止執行,直到接到通知或者被中斷為止。在調用wait()方法之前,線程必須獲得該對象的對象級別鎖,只能在同步方法或者同步塊中調用wait()方法。在執行wait()方法后,當前線程釋放鎖。在從wait()返回前,線程與其他線程競爭重新獲得鎖。如果調用wait()時沒有持有適當的鎖,就會拋出IllegalMonitorStateException異常,它是RuntimeException的一個子類。因此不需要進行異常捕獲。
此處有個面試題,是關于為什么wait()方法必須在同步中?占小狼的公眾號給出了答案,lost wake up問題,作者給出了生產和消費的模式距離來說明lost wake up問題,并給出要解決就必須同步,獲取同一對象鎖,連接如下:
阿里面試題,為什么wait()方法要放在同步塊中??mp.weixin.qq.com(2)notify()方法也需要在同步方法或者同步代碼塊中調用,在調用前,線程必須獲得該對象級別的鎖,如果調用notify()時沒有持有適當的鎖,就會拋出IllegalMonitorStateException異常。該方法用來通知那些可能等待對象的對象鎖的其他線程,如果有多個線程等待,則由線程規劃器隨機挑選其中一個呈wait狀態的線程,對其發出notify,并使它等待獲取該對象的對象鎖。需要說明的是,在執行notify()方法后,當前線程不會馬上釋放鎖,呈wait狀態的線程也不會馬上獲得鎖,必須等到notify()方法的線程執行完,走出同步代碼塊或則方法的時候,當前線程才會釋放鎖,wait狀態的線程才可以獲得鎖。
notify()方法可以隨機喚醒等待隊列中等待同一共享資源的一個線程,并使線程退出等待隊列,進入可運行的狀態,該方法一次只可以喚醒一個線程。
notifyAll()方法是可以喚醒所有正在等待隊列中等待同一共享資源的全部線程,讓其從等待狀態退出,進入可運行狀態,誰的優先級高,誰將會先被執行,也有可能隨機執行,取決于JVM虛擬機的實現。
下面這段代碼,因為沒有“對象監視器”,沒有同步鎖的原因,所以出現了異常
package異常:
Exception下面這段代碼,雖然使用了synchronized關鍵字,而且wait方法也在同步塊中,但是因為當前線程main被掛起,一直處于等待,所以wait()方法后面的代碼都沒有執行機會。
package運行結果:
sync下面這段代碼實現了線程間的通信,線程A先啟動執行,然后調用wait方法,線程睡眠3秒,然后線程B啟動執行,并執行了notify()方法,通知喚醒wait()的線程,當線程B執行完synchronized同步代碼塊,然后釋放了對象鎖,wait()的線程獲取到了對象鎖,然后繼續執行。
package運行結果:
begin下面這段代碼,是當list中添加元素5個的時候,然后就notify()另外一個wait()的線程。
package運行結果:
wait從運行結果可以看出,最開始是wait begin,結束是wait end。
線程的生命周期:
大致分為創建、可運行、運行、阻塞、銷毀等五個狀態。
其中可運行狀態和運行狀態可以相互轉換,阻塞狀態和可運行狀態可以相互轉換。
線程進入Runnable狀態的情況:
(1)調用sleep()方法后經過的時間超過了指定的休眠時間
(2)線程調用的阻塞IO已經返回,阻塞方法執行完畢
(3)線程成功得獲得了試圖同步的監視器
(4)線程正在等待某個通知,其他線程發出了通知
(5)處于掛起狀態的線程調用了resume方法恢復線程
線程出現阻塞狀態的情況:
(1)線程調用sleep方法,主動放棄占用的處理器資源
(2)線程調用了阻塞式IO方法,在方法返回前,該線程被阻塞
(3)線程試圖獲得一個同步監視器,但是該同步監視器正被其他線程所持有
(4)線程等待某個通知
(5)程序調用了suspend()方法,掛起該線程,此方法容易導致死鎖,應該避免調用。
wait方法執行后,鎖會自動釋放;notify()方法執行后,鎖不會自動釋放,除非執行完對應的synchronized方法,才會釋放鎖;sleep方法也是不釋放鎖的(????sleep方法不是指定線程休眠時間,休眠時間過后,線程就i 重新獲得CPU,去執行嗎????我的理解:多線程情況下,其中一個線程在同步塊中被指定休眠時間,這個線程是在休眠期間不會釋放鎖,在休眠結束,同步塊執行完以后就會釋放對象鎖)。
執行完同步代碼塊會釋放對象鎖;
在執行同步代碼塊的過程中,如果遇到異常導致線程終止,鎖也會被釋放;
在執行同步代碼塊的過程中,執行了鎖所屬對象的wait()方法,這個線程會釋放對象鎖,而此線程對象會進入線程等待池中,等待被喚醒。
wait(long)方法:等待某一時間內是否有線程對鎖進行喚醒,如果超過這個時間則自動喚醒。
下面代碼使用wait,分別有兩個線程執行,都執行了同步方法,從控制臺可以看出,程序依然沒有執行完,正是因為A線程執行了wait()方法后,釋放了對象鎖,B線程才可以獲取對象鎖,然后執行同步代碼塊,執行wait。
package運行結果:
begin下面的程序中使用了wait和notify結合,其中wait執行完,其他線程還可以繼續執行同步代碼塊,但是執行到notify的時候,程序就一直不能結束,原因是notify()方法指定完后沒有釋放對象鎖,所以才導致這個問題發生,代碼和運行結果如下所示:
package begin當interrupt()方法和wait()方法相遇,下面是示例代碼和運行結果:
package begin下面這段代碼是關于notify()方法,一次只可以喚醒一個線程(隨機)的驗證:
package程序運行結果:
begin多線程中的生產者和消費者模式:
(1)一個生產者和一個消費者:操作值
package運行結果:set和get交替執行
set(2)多生產者與多消費者:操作值:假死
下面的這段代碼,因為存在使用notify(),可能生產喚醒生產者,消費者喚醒消費者,所以會造成假死狀態。
package運行結果:
productor總結
以上是生活随笔為你收集整理的educoder 使用线程锁(lock)实现线程同步_线程间的通信(一)的全部內容,希望文章能夠幫你解決所遇到的問題。
- 上一篇: 御馔津最新御魂搭配方法
- 下一篇: 王者荣耀李元芳皮肤什么时候返场