中文字幕av专区_日韩电影在线播放_精品国产精品久久一区免费式_av在线免费观看网站

溫馨提示×

溫馨提示×

您好,登錄后才能下訂單哦!

密碼登錄×
登錄注冊×
其他方式登錄
點擊 登錄注冊 即表示同意《億速云用戶服務條款》

Java 中怎么防止在線程阻塞與喚醒時死鎖

發布時間:2021-07-24 13:53:06 來源:億速云 閱讀:219 作者:Leah 欄目:編程語言

本篇文章為大家展示了Java 中怎么防止在線程阻塞與喚醒時死鎖,內容簡明扼要并且容易理解,絕對能使你眼前一亮,通過這篇文章的詳細介紹希望你能有所收獲。

Java并發編程:多線程如何實現阻塞與喚醒  說到suspend與resume組合有死鎖傾向,一不小心將導致很多問題,甚至導致整個系統崩潰。接著看另外一種解決方案,我們可以使用以對象為目標的阻塞,即利用Object類的wait()和notify()方法實現線程阻塞。當線程到達監控對象時,通過wait方法會使線程進入到等待隊列中。而當其它線程調用notify時則可以使線程重新回到執行隊列中,得以繼續執行

Java 中怎么防止在線程阻塞與喚醒時死鎖

 思維不同

針對對象的阻塞編程思維需要我們稍微轉變下思維,它與面向線程阻塞思維有較大差異。如前面的suspend與resume只需在線程內直接調用就能完成掛起恢復操作,這個很好理解。而如果改用wait與notify形式則是通過一個object作為信號,可以將其看成是一堵門。object的wait()方法是鎖門的動作,notify()是開門的動作。某一線程一旦關上門后其他線程都將阻塞,直到別的線程打開門。?

Java 中怎么防止在線程阻塞與喚醒時死鎖

如圖所示,一個對象object調用wait()方法則像是堵了一扇門。線程一、線程二都將阻塞,然后線程三調用object的notify()方法打開門,準確地說是調用了notifyAll()方法,notify()僅僅能讓線程一或線程二其中一條線程通過)。最終線程一、線程二得以通過。

 死鎖問題解決了嗎?

使用wait與notify能在一定程度上避免死鎖問題,但并不能完全避免,它要求我們必須在編程過程中避免死鎖。在使用過程中需要注意的幾點是:

  • 首先,wait與notify方法是針對對象的,調用任意對象的wait()方法都將導致線程阻塞,阻塞的同時也將釋放該對象的鎖。相應地,調用任意對象的notify()方法則將隨機解除該對象阻塞的線程,但它需要重新獲取改對象的鎖,直到獲取成功才能往下執行。

  • 其次,wait與notify方法必須在synchronized塊或方法中被調用,并且要保證同步塊或方法的鎖對象與調用wait與notify方法的對象是同一個。如此一來在調用wait之前當前線程就已經成功獲取某對象的鎖,執行wait阻塞后當前線程就將之前獲取的對象鎖釋放。當然假如你不按照上面規定約束編寫,程序一樣能通過編譯,但運行時將拋出IllegalMonitorStateException異常,必須在編寫時保證用法正確。

  • 最后,notify是隨機喚醒一條阻塞中的線程并讓之獲取對象鎖,進而往下執行,而notifyAll則是喚醒阻塞中的所有線程,讓他們去競爭該對象鎖,獲取到鎖的那條線程才能往下執行。

 改進例子

我們通過wait與notify改造前面的例子,代碼如下。改造的思想就是在MyThread中添加一個標識變量,一旦變量改變就相應地調用wait和notify阻塞喚醒線程。由于在執行wait后將釋放synchronized(this)鎖住的對象鎖,此時System.out.println("running….");早已執行完畢,System類out對象不存在死鎖問題。

Java 中怎么防止在線程阻塞與喚醒時死鎖

Java 中怎么防止在線程阻塞與喚醒時死鎖

 Park與UnPark

wait與notify組合的方式看起來是個不錯的解決方式,但其面向的主體是對象object,阻塞的是當前線程,而喚醒的是隨機的某個線程或所有線程,偏重于線程之間的通信交互。假如換個角度,面向的主體是線程的話,我就能輕而易舉地對指定的線程進行阻塞喚醒,這個時候就需要LockSupport,它提供的park與unpark方法分別用于阻塞和喚醒.而且它提供避免死鎖和競態條件,很好地代替suspend和resume組合。

Java 中怎么防止在線程阻塞與喚醒時死鎖

用park與unpark改造上述例子,代碼如下。把主體換成線程進行的阻塞看起來貌似比較順眼,而且由于park與unpark方法控制的顆粒度更加細小,能準確決定線程在某個點停止,進而避免死鎖的產生。例如此例中在執行System.out.println前線程就被阻塞了,于是不存在因競爭System類out對象而產生死鎖,即便在執行System.out.println后線程才阻塞也不存在死鎖問題,因為鎖已釋放。?

Java 中怎么防止在線程阻塞與喚醒時死鎖

 LockSupport 優勢

LockSupport類為線程阻塞喚醒提供了基礎,同時,在競爭條件問題上具有wait和notify無可比擬的優勢。使用wait和notify組合時,某一線程在被另一線程notify之前必須要保證此線程已經執行到wait等待點,錯過notify則可能永遠都在等待,另外notify也不能保證喚醒指定的某線程。反觀LockSupport,由于park與unpark引入了許可機制,許可邏輯為:  

  • park將許可在等于0的時候阻塞,等于1的時候返回并將許可減為0。 

  • unpark嘗試喚醒線程,許可加1。

根據這兩個邏輯,對于同一條線程,park與unpark先后操作的順序似乎并不影響程序正確地執行。假如先執行unpark操作,許可則為1,之后再執行park操作,此時因為許可等于1直接返回往下執行,并不執行阻塞操作。 最后,LockSupport的park與unpark組合真正解耦了線程之間的同步,不再需要另外的對象變量存儲狀態,并且也不需要考慮同步鎖,wait與notify要保證必須有鎖才能執行,而且執行notify操作釋放鎖后還要將當前線程扔進該對象鎖的等待隊列,LockSupport則完全不用考慮對象、鎖、等待隊列等問題。

上述內容就是Java 中怎么防止在線程阻塞與喚醒時死鎖,你們學到知識或技能了嗎?如果還想學到更多技能或者豐富自己的知識儲備,歡迎關注億速云行業資訊頻道。

向AI問一下細節

免責聲明:本站發布的內容(圖片、視頻和文字)以原創、轉載和分享為主,文章觀點不代表本網站立場,如果涉及侵權請聯系站長郵箱:is@yisu.com進行舉報,并提供相關證據,一經查實,將立刻刪除涉嫌侵權內容。

AI

凌源市| 略阳县| 婺源县| 泽州县| 新巴尔虎右旗| 高碑店市| 页游| 湟中县| 增城市| 图木舒克市| 广饶县| 龙川县| 阿坝县| 嵊州市| 中西区| 微山县| 崇礼县| 万年县| 玉门市| 河间市| 嵊泗县| 建始县| 罗江县| 康定县| 揭西县| 库车县| 桓仁| 云霄县| 聂荣县| 龙口市| 安陆市| 罗平县| 色达县| 习水县| 岱山县| 安阳县| 漾濞| 灌阳县| 崇明县| 木兰县| 安仁县|