【多線程初階】死鎖的產生 如何避免死鎖

文章目錄

  • 關于死鎖
    • 一.死鎖的三種情況
      • 1.一個線程,一把鎖,連續多次加鎖
      • 2.兩個線程,兩把鎖
      • 3.N個線程,M把鎖 --哲學家就餐問題
    • 二.如何避免死鎖
      • 死鎖是如何構成的(四個必要條件)
      • 打破死鎖
    • 三.死鎖小結

關于死鎖

一.死鎖的三種情況

在這里插入圖片描述

  • 1.一個線程,一把鎖,連續多次加鎖 -->由synchronized 鎖解決
  • 2.兩個線程,兩把鎖,每個線程獲取到一把鎖之后,嘗試獲取對方的鎖
  • 3.N個線程,M把鎖 -->一個經典的模型,哲學家就餐問題

1.一個線程,一把鎖,連續多次加鎖

在這里插入圖片描述

一個線程,一把鎖,連續多次加鎖,在實際學習和工作中,是很容易被寫出來的,一旦方法調用的層次比較深,就搞不好容易出現這樣的情況,想要解除阻塞,需要 往下執行,想要往下執行,就需要等待第一次的鎖被釋放,這樣就形成了死鎖(dead lock),就如同下面的Demo18,一個線程對同一把鎖進行多次加鎖,但是運行出來結果沒錯

為了解決當方法調用層次比較深出現一個線程,一把鎖,多次加鎖形成死鎖的情況,Java中的synchronized 就引入了可重入概念,在上一篇博客 synchronized關鍵字里有詳細解釋,本篇博客不再贅述

代碼示例:

class Counter{private int count = 0;synchronized public void add(){count++;}public int get(){return count;}public synchronized  static void func(){synchronized (Counter.class){}}}
public class Demo18 {public static void main(String[] args) throws InterruptedException {Object locker = new Object();Counter counter = new Counter();Thread t1 = new Thread(() ->{for (int i = 0; i < 50000; i++) {counter.add();}});Thread t2 = new Thread(() ->{for (int i = 0; i < 50000; i++) {counter.add();}});t1.start();t2.start();t1.join();t2.join();System.out.println("count="+counter.get());}
}

在這里插入圖片描述

2.兩個線程,兩把鎖

兩個線程,兩把鎖,每個線程獲取到一把鎖之后,嘗試獲取對方的鎖

用生活中的實際場景,舉例說明:
比如,吃餃子~~,朝新喜歡蘸醬油吃,小舟喜歡蘸醋吃,后來兩人都習慣了對方的習慣,兩人都是同時蘸醋和醬油吃餃子,朝新拿起醬油,小舟拿起醋
朝新說:你把醋給我,我用完了,全都給你
小舟說:不行,你把醬油先給我,我用完了,全都給你

此時兩個線程互不相讓,就會構成死鎖~~
還比如,房鑰匙鎖車里了,車鑰匙鎖家里了

代碼示例:

public class Demo20 {public static void main(String[] args) throws InterruptedException {Object lock1 = new Object();Object lock2 = new Object();Thread t1 =new Thread(() ->{synchronized (lock1){//朝新拿起醬油try {Thread.sleep(1000);} catch (InterruptedException e) {e.printStackTrace();}//朝新嘗試拿起醋synchronized (lock2){System.out.println("t1 線程兩個鎖都獲取到");}}});Thread t2 =new Thread(() ->{synchronized (lock2){//小舟拿起醋try {Thread.sleep(1000);} catch (InterruptedException e) {e.printStackTrace();}//小舟嘗試拿起醬油synchronized (lock1){System.out.println("t2 線程兩個鎖都獲取到");}}});t1.start();t2.start();t1.join();t2.join();}
}

在這里插入圖片描述

必須是,拿到第一把鎖,再拿第二把鎖(不能釋放第一把鎖)

在這里插入圖片描述
其中加入sleep的作用:

在這里插入圖片描述
加入sleep就是為了確保上述錯誤代碼構成死鎖

如果讓我們手寫一個出現死鎖的代碼,就是要通過上述代碼,寫兩個線程兩把鎖,注意要精確控制好加鎖的順序,不進行控制的話,隨機調度就有可能不構成死鎖了

3.N個線程,M把鎖 --哲學家就餐問題

在這里插入圖片描述

大部分情況下,上述模型,可以很好的運轉,但是在一些極端情況下會造成死鎖
像是,同一時刻,大家都想吃面條,同時拿起左手的筷子,此時任何一個線程都無法拿起右手的筷子,任何一個哲學家都吃不成面條
每個線程,都不會放下手里的筷子,而是阻塞等待,構成死鎖

上述場景雖說非常極端,但是在以后的學習和工作中,比如我們以后會做服務器開發,同時為很多個用戶提供服務,假設上述場景,即使出現死鎖的概率是1%%,服務器可能一天要處理幾千萬的請求(比如百度,一天要處理10億量級的請求),這樣就會出現10萬次死鎖情況,就比如溫總理說的:在咱們國家,再小的問題,乘以13億都是大問題~~,那么如何避免死鎖問題呢?

二.如何避免死鎖

死鎖是如何構成的(四個必要條件)

在這里插入圖片描述

  • 1.鎖是互斥的,一個線程拿到鎖之后,另一個線程再嘗試獲取鎖,必須要阻塞等待 (鎖的基本性質)
  • 2.鎖是不可搶占的(不可剝奪),線程1拿到鎖 線程2也嘗試獲取這個鎖,線程2必須阻塞等待,而不是線程2直接把鎖搶過來 (鎖的基本特性)
  • 3.請求和保持,一個線程拿到鎖1 之后不釋放鎖1的前提下,去獲取鎖2
  • 4.循環等待,多個線程,多把鎖之間的等待過程,構成了"循環",A等待B,B等待C,C等待A

以上四個形成死鎖的必要條件,其中1和2都是鎖自己的基本性質和特性,至少,Java中的synchronized鎖是遵守這兩點的,各種語言中內置的鎖/主流的鎖,都是遵守這兩點的,這兩點我們改變不了

只要破壞上述的3 ,4任何一個條件都能夠打破死鎖

打破死鎖

  • 1.打破必要條件3 :請求和保持
    如果是先放下左手的筷子,再去拿右手的筷子,就不會構成死鎖了,也就是代碼中加鎖的時候,不要"嵌套加鎖"

代碼示例:

public class Demo20 {public static void main(String[] args) throws InterruptedException {Object lock1 = new Object();Object lock2 = new Object();Thread t1 =new Thread(() ->{synchronized (lock1){//朝新拿起醬油try {Thread.sleep(1000);} catch (InterruptedException e) {e.printStackTrace();}}//朝新嘗試拿起醋synchronized (lock2){System.out.println("t1 線程兩個鎖都獲取到");}});Thread t2 =new Thread(() ->{synchronized (lock2){//小舟拿起醋try {Thread.sleep(1000);} catch (InterruptedException e) {e.printStackTrace();}}//小舟嘗試拿起醬油synchronized (lock1){System.out.println("t2 線程兩個鎖都獲取到");}});t1.start();t2.start();t1.join();t2.join();}
}

在這里插入圖片描述
這種破壞死鎖的方法不夠通用,有些情況下,確實需要拿到多個鎖,再進行某個操作的(嵌套,很難避免)

  • 2.打破必要條件4 :循環等待

約定好加鎖的順序,就可以破除循環等待了,我們約定好,每個線程加鎖的時候,永遠是先獲取序號小的鎖,后獲取序號大的鎖

在這里插入圖片描述
在這里插入圖片描述
在這里插入圖片描述
在這里插入圖片描述
在這里插入圖片描述

通過上述哲學家就餐模型,我們可以觀察到,只要規定好加鎖的順序,就可以打破循環等待,從而避免死鎖問題

我們使用上述吃餃子過程中出現的死鎖問題來觀察,通過破除循環等待,也就是規定好加鎖順序后,是如何避免死鎖問題的

public class Demo20 {public static void main(String[] args) throws InterruptedException {Object lock1 = new Object();Object lock2 = new Object();Thread t1 =new Thread(() ->{synchronized (lock1){//朝新拿起醬油System.out.println("t1 拿到locker1");try {Thread.sleep(1000);} catch (InterruptedException e) {e.printStackTrace();}//朝新嘗試拿起醋synchronized (lock2){System.out.println("t1 線程兩個鎖都獲取到 吃面條");}}});Thread t2 =new Thread(() ->{synchronized (lock1){//小舟拿起醋System.out.println("t2 拿到locker1");try {Thread.sleep(1000);} catch (InterruptedException e) {e.printStackTrace();}//小舟嘗試拿起醬油synchronized (lock2){System.out.println("t2 線程兩個鎖都獲取到 吃面條");}}});t1.start();t2.start();t1.join();t2.join();}
}

在這里插入圖片描述

三.死鎖小結

在這里插入圖片描述

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

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

相關文章

【NLP基礎知識系列課程-Tokenizer的前世今生第二課】NLP 中的 Tokenizer 技術發展史

從詞表到子詞&#xff1a;Tokenizer 的“進化樹” 我們常說“語言模型是理解人類語言的工具”&#xff0c;但事實上&#xff0c;模型能不能“理解”&#xff0c;關鍵要看它接收到了什么樣的輸入。而 Tokenizer&#xff0c;就是這一輸入階段的設計者。 在 NLP 的發展歷程中&am…

Rust 學習筆記:循環和迭代器的性能比較

Rust 學習筆記&#xff1a;循環和迭代器的性能比較 Rust 學習筆記&#xff1a;循環和迭代器的性能比較示例 1示例 2總結 Rust 學習筆記&#xff1a;循環和迭代器的性能比較 示例 1 我們運行一個基準測試&#xff0c;將《福爾摩斯探案集》的全部內容加載到一個字符串中&#x…

pod創建和控制

一、引言 ?主題?&#xff1a;pod以及控制器模式中的Deployment作用。?控制器模式&#xff1a;使用一種API對象&#xff08;如Deployment&#xff09;管理另一種API對象&#xff08;如Pod&#xff09;的方式。 二、容器鏡像與配置文件 ?容器鏡像?&#xff1a;應用開發者…

HTML實戰:愛心圖的實現

設計思路 使用純CSS創建多種風格的愛心 添加平滑的動畫效果 實現交互式愛心生成器 響應式設計適應不同設備 優雅的UI布局和色彩方案 <!DOCTYPE html> <html lang"zh-CN"> <head> <meta charset"UTF-8"> <meta nam…

2022年 中國商務年鑒(excel電子表格版)

2022年 中國商務年鑒&#xff08;excel電子表格版&#xff09;.ziphttps://download.csdn.net/download/2401_84585615/89772883 https://download.csdn.net/download/2401_84585615/89772883 《中國商務年鑒2022》是由商務部國際貿易經濟合作研究院主辦的年度統計資料&#xf…

Redis核心數據結構操作指南:字符串、哈希、列表詳解

注&#xff1a;此為蒼穹外賣學習筆記 Redis作為高性能的鍵值數據庫&#xff0c;其核心價值來自于豐富的數據結構支持。本文將深入解析字符串&#xff08;String&#xff09;、哈希&#xff08;Hash&#xff09;、**列表&#xff08;List&#xff09;**三大基礎結構的操作命令&…

如何以 9 種方式將照片從 iPhone 傳輸到筆記本電腦

您的 iPhone 可能充滿了以照片和視頻形式捕捉的珍貴回憶。無論您是想備份它們、在更大的屏幕上編輯它們&#xff0c;還是只是釋放設備上的空間&#xff0c;您都需要將照片從 iPhone 傳輸到筆記本電腦。幸運的是&#xff0c;有 9 種方便的方法可供使用&#xff0c;同時滿足 Wind…

如何使用Python從MySQL數據庫導出表結構到Word文檔

在開發和維護數據庫的過程中&#xff0c;能夠快速且準確地獲取表結構信息是至關重要的。本文將向您展示一種簡單而有效的方法&#xff0c;利用Python腳本從MySQL數據庫中提取指定表的結構信息&#xff0c;并將其導出為格式化的Word文檔。此方法不僅提高了工作效率&#xff0c;還…

寫作-- 復合句練習

文章目錄 練習 11. 家庭的支持和老師的指導對學生的學術成功有積極影響。2. 缺乏準備和未能適應通常會導致在挑戰性情境中的糟糕表現。3. 吃垃圾食品和忽視鍛煉可能導致嚴重的健康問題,因此人們應注重保持均衡的生活方式。4. 昨天的大雨導致街道洪水泛濫,因此居民們遷往高地以…

QT使用說明

QT環境準備 推薦Ubuntu平臺上使用&#xff0c;配置簡單&#xff0c;坑少。 Ubuntu 20.04 安裝 sudo apt-get install qt5-default -y sudo apt-get install qtcreator -y sudo apt-get install -y libclang-common-8-dev啟動 qtcreatorHelloWorld 打開 Qt Creator。選擇 …

React 第四十九節 Router中useNavigation的具體使用詳解及注意事項

前言 useNavigation 是 React Router 中一個強大的鉤子&#xff0c;用于獲取當前頁面導航的狀態信息。 它可以幫助開發者根據導航狀態優化用戶體驗&#xff0c;如顯示加載指示器、防止重復提交等。 一、useNavigation核心用途 檢測導航狀態&#xff1a;判斷當前是否正在進行…

列表單獨展開收起同時關閉其余子項的問題優化

如圖所示&#xff0c;當在列表中&#xff0c;需要分別單獨點開子選項時&#xff0c;直接這樣用一個index參數判斷即可&#xff0c;非常簡單方便&#xff0c;只需要滿足點開當前index,然后想同index用null值自動關閉即可

WPF【11_5】WPF實戰-重構與美化(MVVM 實戰)

11-10 【重構】創建視圖模型&#xff0c;顯示客戶列表 正式進入 MVVM 架構的代碼實戰。在之前的課程中&#xff0c; Model 和 View 這部分的代碼重構實際上已經完成了。 Model 就是在 Models 文件夾中看到的兩個文件&#xff0c; Customer 和 Appointment。 而 View 則是所有與…

LangChain-結合魔塔社區modelscope的embeddings實現搜索

首先要安裝modelscope pip install modelscope 安裝完成后測試 from langchain_community.embeddings import ModelScopeEmbeddingsembeddings ModelScopeEmbeddings(model_id"iic/nlp_gte_sentence-embedding_chinese-base")text "這是一個測試句子"…

可定制化貨代管理系統,適應不同業務模式需求!

在全球化貿易的浪潮下&#xff0c;貨運代理行業扮演著至關重要的角色。然而&#xff0c;隨著市場競爭的日益激烈&#xff0c;貨代企業面臨著越來越多的挑戰&#xff1a;客戶需求多樣化、業務流程復雜化、運營成本上升、利潤空間壓縮……這些挑戰迫使貨代企業不斷尋求創新和突破…

Lyra學習筆記2 GFA_AddComponents與ULyraPlayerSpawningManagerComponent

目錄 前言GameFeatureAction_AddComponentsULyraPlayerSpawningManagerComponent緩存所有PlayerStart位置選擇位置 前言 1.以control模式為例 2.比較散&#xff0c;想單獨拿出一篇梳理下Experience的流程 GameFeatureAction_AddComponents 這部分建議看 《InsideUE5》GameFeatu…

進程生命周期

進程生命周期 Linux是多任務操作系統&#xff0c;系統中的每個進程能夠分時復用CPU時間片&#xff0c;通過有效的進程調度策略實現多任務并行執行。進程在被CPU調度運行&#xff0c;等待CPU資源分配以及等待外部事件時會處于不同的狀態。進程狀態如下&#xff1a; 創建狀態&a…

文字轉圖片的字符畫生成工具

軟件介紹 今天要介紹的這款軟件可以將文字轉換成圖片的排列形式&#xff0c;非常適合需要將文字圖形化的場景&#xff0c;建議有需要的朋友收藏。 軟件名稱與用途 這款軟件名為《字符畫大師》&#xff0c;是一款在網吧等場所非常流行的聊天輔助工具&#xff0c;其主要功能就…

歷年南京大學計算機保研上機真題

2025南京大學計算機保研上機真題 2024南京大學計算機保研上機真題 2023南京大學計算機保研上機真題 在線測評鏈接&#xff1a;https://pgcode.cn/school Count Number of Binary Strings 題目描述 Given a positive integer n n n ( 3 ≤ n ≤ 90 3 \leq n \leq 90 3≤n≤…

王樹森推薦系統公開課 排序06:粗排模型

shared bottom 表示神經網絡被所有特征共享。精排模型主要開銷在神經網絡&#xff0c;神經網絡很大且很復雜。 每做一次推薦&#xff0c;用戶塔只做一次推理。物品塔存放入向量數據庫。 后期融合模型常用于召回&#xff0c;前期融合模型常用于精排。 物品塔短時間內比較穩…