【Java多線程】分析線程加鎖導致的死鎖問題以及解決方案

目錄

1、線程加鎖

2、死鎖問題的三種經典場景

2.1、一個線程一把鎖

2.2、兩個線程兩把鎖

2.3、N個線程M把鎖(哲學家就餐問題)

?3、解決死鎖問題


1、線程加鎖

其中 locker 可以是任意對象,進入 synchronized 修飾的代碼塊, 相當于加鎖,退出 synchronized 修飾的代碼塊, 相當解鎖。

如果一個線程,針對一個對象加上鎖之后,其他線程也嘗試對這個對象加鎖,就會導致鎖競爭進而引起阻塞(BLOCKED),這個阻塞會一直持續到上一個線程釋放鎖為止。

如果是兩個線程分別針對不同的對象進行加鎖,此時不會由鎖競爭,也就不會阻塞。

出現鎖競爭進而引起阻塞狀態,這個阻塞會一直持續到下一個線程釋放鎖為止。

但是,設想一個場景,共有AB兩個線程,此時A線程因為鎖競爭進入阻塞狀態,而如果此時B線程恰巧也正在阻塞狀態,由于AB線程都進入了阻塞狀態,此時進程無法運行,出現死鎖問題。下面針對死鎖問題的出現以及解決方法展開討論。

2、死鎖問題的三種經典場景

2.1、一個線程一把鎖

public static void main(String[] args) {Object locker = new Object();Thread t = new Thread(() -> {synchronized (locker) {   //兩次加鎖,加的是同一把鎖synchronized (locker) {   //兩次加鎖,加的是同一把鎖System.out.println("hello synchronized");}}});t.start();
}

需要注意的是,這里最直觀的感覺是進行了兩次加鎖,會發生鎖沖突。第一次針對locker加鎖之后,在還沒釋放鎖的時候又嘗試對locker加鎖,理論會出現鎖沖突。

至于事實上是否會出現所沖突進而出現死鎖,需要分情況討論:

1、如果是不可重入鎖,則就會出現鎖競爭引起死鎖。

2、如果是可重入鎖,則不會出現鎖競爭引起死鎖,Java中的鎖就是可重入鎖,因此可以正常打印。

可以把這種情況理解成:【屋鑰匙鎖在了屋里】

2.2、兩個線程兩把鎖

package thread;public class ThreadDemo22 {public static void main(String[] args) {Object A = new Object();Object B = new Object();Thread t1 = new Thread(() -> {synchronized (A) {// sleep一下, 給 t2 時間, 讓 t2 也能拿到 Btry {Thread.sleep(1000);} catch (InterruptedException e) {e.printStackTrace();}// 嘗試獲取 B, 并沒有釋放 Asynchronized (B) {System.out.println("t1 拿到了兩把鎖!");}}});Thread t2 = new Thread(() -> {synchronized (A) {// sleep一下, 給 t1 時間, 讓 t1 能拿到 Atry {Thread.sleep(1000);} catch (InterruptedException e) {e.printStackTrace();}// 嘗試獲取 A, 并沒有釋放 Bsynchronized (B) {System.out.println("t2 拿到了兩把鎖!");}}});t1.start();t2.start();}
}

兩個線程,兩把鎖。線程A獲取到鎖A,線程B獲取到鎖B,在沒釋放鎖AB的前提下,線程A嘗試獲取鎖B,線程B嘗試獲取鎖A,就會出現死鎖。

可以把這種情況理解成:【屋鑰匙鎖在了車里,車鑰匙鎖在了屋里】

2.3、N個線程M把鎖(哲學家就餐問題)

首先假設一個場景,一張圓桌上坐著五個人,每個人面前都有一碗面條,桌子上一共有五根筷子(不是五雙),而將五根筷子分別擺放在兩人各自之間,如下圖。

????????要想吃面條,需要拿起自己身旁的兩根筷子(左右兩根,只能拿身邊的這兩根)。假設此時A拿起了左右筷子吃面條,此時B就無法吃,因為A正在使用B的左筷子,B目前只能拿起一根右筷子,并且開始等待,等待A放下筷子,再拿起左筷子吃面條(此處的等待只有拿到另外一根筷子后才會停止,并且等待的同時不會放下已經拿起的筷子)。同理E也一樣。

????????此處討論的問題中N等于M。我們將線程比作人筷子比作鎖此時B所處的狀態可以比作鎖競爭引起的阻塞狀態。大家可以試著想想各種其他不同的情況,始終都能保證桌上5個人至少有一人正在吃面條,除了一種特殊的極端情況下:

? ? ? ? 極端情況下,會出現所有人同時都拿了同一側的筷子(例如都拿了左筷子),導致所有人都不能拿起另一側的筷子而都進入阻塞,等待著別人放下筷子后自己再拿起來。但是此時又因為沒有一個人能吃的上面條,因此永遠不會有人放下筷子,出現死鎖。

????????這個問題也被人稱之為:哲學家就餐問題。

?3、解決死鎖問題

要想解決死鎖情況,就得先討論產生死鎖的原因:

死鎖產生的四個必要條件(缺一不可)

由于是必要條件,只需要破壞其中一種條件,就可以讓死鎖解開。?

  1. 互斥使用。一個線程拿到了這把鎖,另一個線程也想獲取,就需要阻塞等待,這是鎖最基本的特性,不好破壞。
  2. 不可搶占。一個線程拿到了鎖之后,只能主動解鎖,不能讓別的線程強行把鎖搶走,這也是鎖最基本的特性,不好破壞。
  3. 請求保持。一個線程拿到了鎖A,在持有鎖A的前提下,嘗試獲取鎖B。這些場景下必須需要這樣使用,也不好破壞。
  4. 循環等待/環路等待,是一種代碼結構,是最容易破壞。

由上述分析可以得知,想要解決死鎖問題,要從破壞循環等待/環路等待入手。

引入加鎖順序的規則就是很好破解循環等待的辦法,即給每一個鎖編號,規定只能按照鎖的序號順序拿起,就能打破循環等待。

舉例說明:

????????依然是是上面的哲學家就餐問題,此時給筷子編號序號之后,要求只能按照順序由小到大拿起,此時就算是所有人同時拿起筷子,C先拿1,B先拿2,A先拿3,E先拿4,此時D按照規定應該拿起1,但是此時C正拿著1,因此此時D還沒有機會拿起5,就直接進入阻塞狀態。此場景下E就能拿起5開始吃面,E放下筷子A就接著吃,依此類推,就將可能出現的死鎖問題破解了。

?

【博主推薦】?

【Java多線程】線程中幾個常見的屬性以及狀態-CSDN博客icon-default.png?t=N7T8https://blog.csdn.net/zzzzzhxxx/article/details/136122127?spm=1001.2014.3001.5501【Java多線程】Thread類的基本用法-CSDN博客icon-default.png?t=N7T8https://blog.csdn.net/zzzzzhxxx/article/details/136121421?spm=1001.2014.3001.5501【Java多線程】對進程與線程的理解-CSDN博客icon-default.png?t=N7T8https://blog.csdn.net/zzzzzhxxx/article/details/136115808?spm=1001.2014.3001.5501

如果覺得作者寫的不錯,求給博主一個大大的點贊支持一下,你們的支持是我更新的最大動力!

如果覺得作者寫的不錯,求給博主一個大大的點贊支持一下,你們的支持是我更新的最大動力!

如果覺得作者寫的不錯,求給博主一個大大的點贊支持一下,你們的支持是我更新的最大動力!

本文來自互聯網用戶投稿,該文觀點僅代表作者本人,不代表本站立場。本站僅提供信息存儲空間服務,不擁有所有權,不承擔相關法律責任。
如若轉載,請注明出處:http://www.pswp.cn/news/696086.shtml
繁體地址,請注明出處:http://hk.pswp.cn/news/696086.shtml
英文地址,請注明出處:http://en.pswp.cn/news/696086.shtml

如若內容造成侵權/違法違規/事實不符,請聯系多彩編程網進行投訴反饋email:809451989@qq.com,一經查實,立即刪除!

相關文章

Java SourceDataLine 播放音頻

Java SourceDataLine 播放音頻 1 依賴2 接口3 實現4 測試 項目Value音頻格式 添加依賴*.wav(JDK 原生支持)*.pcm(JDK 原生支持)*.au(JDK 原生支持)*.aiff(JDK 原生支持)*.mp3mp3spi.jar*.flacjflac-codec.jar 1 依賴 <dependency><groupId>com.googlecode.soundl…

?北郵復試刷題LCR 052. 遞增順序搜索樹__DFS (力扣119經典題變種挑戰)

LCR 052. 遞增順序搜索樹 給你一棵二叉搜索樹&#xff0c;請 按中序遍歷 將其重新排列為一棵遞增順序搜索樹&#xff0c;使樹中最左邊的節點成為樹的根節點&#xff0c;并且每個節點沒有左子節點&#xff0c;只有一個右子節點。 示例 1&#xff1a; 輸入&#xff1a;root [5,…

DataX - 全量數據同步工具

前言 今天是2024-2-21&#xff0c;農歷正月十二&#xff0c;相信今天開始是新的階段&#xff0c;盡管它不是新的周一、某月一日、某年第一天&#xff0c;盡管我是一個很講究儀式感的人。新年剛過去 12 天&#xff0c;再過 3 天就開學咯&#xff0c;開學之后我的大學時光就進入了…

TypeScript01:安裝TypeScript

一、TypeScript 官方網站&#xff1a;https://www.tslang.cn/docs/index.html 練習場&#xff1a;https://www.typescriptlang.org/zh/play 好處&#xff1a; 強類型語言&#xff0c;對JS弱類型的一個良好補充&#xff1b;TS利于大型項目團隊合作&#xff0c;可以一定程度…

這五個軟件測試工具,測試工程師必備

在軟件開發過程中&#xff0c;軟件測試是確保軟件質量和穩定性的關鍵環節。為了幫助開發人員和測試團隊更好地完成這一任務&#xff0c;市面上涌現出眾多軟件測試工具。本文將盤點五個備受推崇的軟件測試工具&#xff0c;它們各具特色&#xff0c;適用于不同的測試場景。 Test…

ChatGPT實戰100例 - (17) 用ChatGPT實現音頻長度測量和音量調整

文章目錄 ChatGPT實戰100例 - (17) 用ChatGPT實現音頻長度測量和音量調整獲取音頻長度pydub獲取音頻長度獲取時長精確到秒格式設定 mutagen獲取音頻長度 調整音量視頻音量調整注意事項 ChatGPT實戰100例 - (17) 用ChatGPT實現音頻長度測量和音量調整 老王媳婦說上次那個pip挺好…

深度學習的學習筆記帖子2

人臉數據集的介紹&#xff1a; https://zhuanlan.zhihu.com/p/362356480 https://blog.csdn.net/bjbz_cxy/article/details/122210641 CASIAWebFace人臉數據集等的github&#xff1a; https://github.com/deepinsight/insightface/blob/master/recognition/datasets/README.md…

藍橋杯基礎知識點9 stack、queue、priority_queue

藍橋杯基礎知識點9 stack、queue、priority_queue 01 stack的定義和結構 stack是一種后進先出&#xff08;LIFO&#xff09;的數據結構&#xff0c;頭文件<stcak>。 template <class T, class Container deque<T>> class stack; T&#xff1a;存儲在stack…

《VitePress 簡易速速上手小冊》第7章 高級功能與動態內容(2024 最新版)

文章目錄 7.1 動態路由與 API 集成7.1.1 基礎知識點解析7.1.2 重點案例&#xff1a;技術博客7.1.3 拓展案例 1&#xff1a;電商網站7.1.4 拓展案例 2&#xff1a;事件管理網站 7.2 狀態管理與 Vuex 使用7.2.1 基礎知識點解析7.2.2 重點案例&#xff1a;用戶認證系統7.2.3 拓展案…

力扣精選算法100道——Z字形變換(模擬專題)

目錄 &#x1f388;了解題意 &#x1f388;算法原理 &#x1f6a9;先處理第一行和最后一行 &#x1f6a9;再處理中間行 &#x1f388;實現代碼 &#x1f388;了解題意 大家看到這個題目的時候肯定是很迷茫的&#xff0c;包括我自己也是搞不清楚題目什么意思&#xff0c;我…

memcpy和strcat的區別

memcpy 函數&#xff1a; memcpy 函數用于在內存之間復制一定數量的字節。memcpy 是按字節進行復制的&#xff0c;可以用于復制任意類型的數據&#xff0c;不僅限于字符串。memcpy 不會自動添加字符串結束符號 \0&#xff0c;因此在復制字符串時&#xff0c;需要確保復制的字節…

喝點小酒-胡謅“編程語言學習”

今天&#xff0c; 與一個小哥們兒&#xff08;學習計算機科學與技術專業的&#xff0c;我兒子&#xff0c;這是真的&#xff09;一塊兒吃飯&#xff08;這頓飯&#xff0c;在家里吃的&#xff0c;吹個牛哈&#xff0c;我做的&#xff0c;三個葷菜、一個素材、一個湯、主食米飯 …

約瑟夫經典問題C++,STL容器queue解法

題目&#xff1a; Description n 個人圍成一圈&#xff0c;從第一個人開始報數,數到 m 的人出列&#xff0c;再由下一個人重新從 1 開始報數&#xff0c;數到m 的人再出圈&#xff0c;依次類推&#xff0c;直到所有的人都出圈&#xff0c;請輸出依次出圈人的編號。 注意&…

[linux]進程間通信(IPC)———共享內存(shm)(什么是共享內存,共享內存的原理圖,共享內存的接口,使用演示)

一、什么是共享內存 共享內存區是最快的&#xff08;進程間通信&#xff09;IPC形式。一旦這樣的內存映射到共享它的進程的地址空間&#xff0c;這些進程間數據傳遞不再涉及到內核&#xff0c;換句話說是進程不再通過執行進入內核的系統調用來傳遞彼此的數據。注意&#xff1a;…

Three.js初學(2)

Three.js初學&#xff08;2&#xff09; 三維坐標系的認識1. 輔助坐標系 光源的影響1. 光材質的影響2. 光源介紹點光源環境光平行光 3. 光源衰減/位置 相機控件1. 引入擴展庫2. 使用方法 三維坐標系的認識 這一章節的主要作用是加強自我對三維坐標空間的認識。 1. 輔助坐標系…

貓頭虎分享已解決Bug || TypeError: Cannot set property ‘innerHTML‘ of null

博主貓頭虎的技術世界 &#x1f31f; 歡迎來到貓頭虎的博客 — 探索技術的無限可能&#xff01; 專欄鏈接&#xff1a; &#x1f517; 精選專欄&#xff1a; 《面試題大全》 — 面試準備的寶典&#xff01;《IDEA開發秘籍》 — 提升你的IDEA技能&#xff01;《100天精通鴻蒙》 …

華為配置直連三層組網隧道轉發示例

配置直連三層組網隧道轉發示例 組網圖形 圖1 配置直連三層組網隧道轉發示例組網圖 業務需求組網需求數據規劃配置思路配置注意事項操作步驟配置文件擴展閱讀 業務需求 企業用戶接入WLAN網絡&#xff0c;以滿足移動辦公的最基本需求。且在覆蓋區域內移動發生漫游時&#xff0c;不…

Linux 系統編程:文件編程

本篇涉及文件的創建、打開、讀和關閉。 文件為操作系統服務和設備提供了一個簡單而一致的 接口 。“接口”指的是一種約定或標準&#xff0c;通過提供一個一致的接口&#xff0c;可以為上層隱藏底層硬件和服務的復雜性&#xff0c;上層無需關注它們的具體實現細節。 比如操作系…

Kafka進階

文章目錄 概要應用場景消息隊列兩種模式kafka的基礎架構分區常見問題小結 概要 kafka的傳統定義&#xff1a;kafka是一個分布式的基于發布\訂閱模式的消息隊列&#xff0c;主要用于大數據實時處理領域。 kafka的最新概念&#xff1a;kafka是一個開源的分布式事件流平臺&#x…

隨機森林模型、模型模擬技術和決策樹模型簡介

隨機森林模型、模型模擬技術和決策樹模型簡介 隨機森林模型 隨機森林模型是一種比較新的機器學習模型&#xff0c;它是通過集成學習的方法將多個決策樹模型組合起來&#xff0c;形成一個更加強大和穩定的模型。隨機森林模型的基本原理是“數據隨機”和“特征隨機”&#xff0…