日韩性视频-久久久蜜桃-www中文字幕-在线中文字幕av-亚洲欧美一区二区三区四区-撸久久-香蕉视频一区-久久无码精品丰满人妻-国产高潮av-激情福利社-日韩av网址大全-国产精品久久999-日本五十路在线-性欧美在线-久久99精品波多结衣一区-男女午夜免费视频-黑人极品ⅴideos精品欧美棵-人人妻人人澡人人爽精品欧美一区-日韩一区在线看-欧美a级在线免费观看

歡迎訪問 生活随笔!

生活随笔

當前位置: 首頁 > 编程资源 > 编程问答 >内容正文

编程问答

什么叫死锁?死锁案例?死锁必须满足哪些条件?如何定位死锁问题?有哪些解决死锁策略?哲学家问题?

發布時間:2024/8/23 编程问答 32 豆豆
生活随笔 收集整理的這篇文章主要介紹了 什么叫死锁?死锁案例?死锁必须满足哪些条件?如何定位死锁问题?有哪些解决死锁策略?哲学家问题? 小編覺得挺不錯的,現在分享給大家,幫大家做個參考.

1.死鎖是什么?

死鎖一定發生在并發環境中,死鎖是一種狀態,當兩個(或者多個線程)相互持有對方所需要的資源,卻又都不主動釋放手中持有的資源,導致大家都獲取不到自己想要的資源,所有相關的線程無法繼續執行。

2.死鎖案例

import java.util.concurrent.ExecutorService; import java.util.concurrent.Executors;/*** @author weijie* @date 2020/4/28 10:43*/ public class DeadLockDemo {Object o1 = new Object();Object o2 = new Object();class Task1 implements Runnable{@Overridepublic void run() {synchronized (o1){System.out.println("task1 start ...");String threadName = Thread.currentThread().getName();System.out.print(threadName + "獲取i1對象鎖--->");/*** 阻塞當前線程*/try {Thread.sleep(1000);} catch (InterruptedException e) {e.printStackTrace();}synchronized (o2){System.out.println("獲取i2對象鎖");}System.out.println("task2 end ...");}}}class Task2 implements Runnable{@Overridepublic void run() {synchronized (o2) {System.out.println("task2 start ...");String threadName = Thread.currentThread().getName();System.out.print(threadName + "獲取i2對象鎖--->");synchronized (o1) {System.out.println("獲取i1對象鎖");}System.out.println("task 2 end ...");}}}public static void main(String[] args) {DeadLockDemo deadLockDemo = new DeadLockDemo();ExecutorService executorService = Executors.newFixedThreadPool(2);executorService.submit(deadLockDemo.new Task1());executorService.submit(deadLockDemo.new Task2());}}

3.死鎖必須滿足的四個條件?

  • 互斥條件:每個資源同時只能被一個線程使用。線程A占用了,線程B一定不能使用,必須等線程A釋放資源后,線程B才能繼續使用。
  • 請求與保持條件:也就是說當線程A占用資源時,由于線程A有其他業務邏輯導致線程阻塞等,此時不能自動釋放資源,如果自動釋放資源那就不會發生死鎖問題。
  • 不剝奪條件:當線程A占用資源時,不能被線程B剝奪、搶占資源。
  • 4.如何用命令行和代碼定位死鎖?

    1.通過命令行定位

  • 通過jps指令獲取服務進程id
  • 56402 MustDeadLock 56403 Launcher 56474 Jps 55051 KotlinCompileDaemon
  • jstack pid指令來打印信息,會出現“Found one Java-level deadlock”表示死鎖,接著我們可以通過打印信息定位死鎖問題
  • Found one Java-level deadlock: ============================= "t2":waiting to lock monitor 0x00007fa06c004a18 (object 0x000000076adabaf0, a java.lang.Object),which is held by "t1" "t1":waiting to lock monitor 0x00007fa06c007358 (object 0x000000076adabb00, a java.lang.Object),which is held by "t2"Java stack information for the threads listed above: =================================================== "t2":at lesson67.MustDeadLock.run(MustDeadLock.java:31)- waiting to lock <0x000000076adabaf0> (a java.lang.Object)- locked <0x000000076adabb00> (a java.lang.Object)at java.lang.Thread.run(Thread.java:748) "t1":at lesson67.MustDeadLock.run(MustDeadLock.java:19)- waiting to lock <0x000000076adabb00> (a java.lang.Object)- locked <0x000000076adabaf0> (a java.lang.Object)at java.lang.Thread.run(Thread.java:748)Found 1 deadlock

    在這里它首先會打印“Found one Java-level deadlock”,表明“找到了一個死鎖”。
    然后是更詳細的信息,從中間這部分的信息中可以看出:
    t2 線程想要去獲取這個尾號為 af0 的鎖對象,但是它被 t1 線程持有,同時 t2 持有尾號為 b00 的鎖對象; 相反,t1 想要獲取尾號為 b00 的鎖對象,但是它被 t2 線程持有,同時 t1 持有的卻是尾號為 af0 的鎖對象, 這就形成了一個依賴環路,發生了死鎖。 最后它還打印出了“Found 1 deadlock.”,

    可以看出,jstack 工具不但幫我們找到了死鎖,甚至還把哪個線程、想要獲取哪個鎖、形成什么樣的環路都告訴我們了,當我們有了這樣的信息之后,死鎖就非常容易定位了,所以接下來我們就可以進一步修改代碼,來避免死鎖了。

    2.代碼定位死鎖

    ThreadMXBean用來定位死鎖問題

    在main方法中添加如下代碼:

    //保證發生死鎖Thread.sleep(3000);System.out.println("定位死鎖信息");ThreadMXBean threadMXBean = ManagementFactory.getThreadMXBean();long[] deadlockedThreads = threadMXBean.findDeadlockedThreads();if(deadlockedThreads != null && deadlockedThreads.length > 0){for (int i= 0; i < deadlockedThreads.length; i++){long deadlockedThread = deadlockedThreads[i];ThreadInfo threadInfo = threadMXBean.getThreadInfo(deadlockedThread);System.out.println("線程id為"+threadInfo.getThreadId()+",線程名為" + threadInfo.getThreadName()+"的線程已經發生死鎖,需要的鎖正被線程"+threadInfo.getLockOwnerName()+"持有。");}}


    可以看出,ThreadMXBean 也可以幫我們找到并定位死鎖,如果我們在業務代碼中加入這樣的檢測,那我們就可以在發生死鎖的時候及時地定位,同時進行報警等其他處理,也就增強了我們程序的健壯性

    5.經典的哲學家問題

    1.問題描述

    哲學家就餐問題也被稱為刀叉問題,或者吃面問題。我們先來描述一下這個問題所要說明的事情,這個問題如下圖所示:

    有 5 個哲學家,他們面前都有一雙筷子,即左手有一根筷子,右手有一根筷子。當然,這個問題有多個版本的描述,可以說是筷子,也可以說是一刀一叉,因為吃牛排的時候,需要刀和叉,缺一不可,也有說是用兩把叉子來吃意大利面。這里具體是刀叉還是筷子并不重要,重要的是必須要同時持有左右兩邊的兩個才行,也就是說,哲學家左手要拿到一根筷子,右手也要拿到一根筷子,在這種情況下哲學家才能吃飯。為了方便理解,我們選取和我國傳統最貼近的筷子來說明這個問題。

    為什么選擇哲學家呢?因為哲學家的特點是喜歡思考,所以我們可以把哲學家一天的行為抽象為思考,然后吃飯,并且他們吃飯的時候要用一雙筷子,而不能只用一根筷子。

    1. 主流程

    我們來看一下哲學家就餐的主流程。哲學家如果想吃飯,他會先嘗試拿起左手的筷子,然后再嘗試拿起右手的筷子,如果某一根筷子被別人使用了,他就得等待他人用完,用完之后他人自然會把筷子放回原位,接著他把筷子拿起來就可以吃了(不考慮衛生問題)。這就是哲學家就餐的最主要流程。

    2. 流程的偽代碼

    我們來看一下這個流程的偽代碼,如下所示:

    while(true) { // 思考人生、宇宙、萬物...think();// 思考后感到餓了,需要拿筷子開始吃飯pick_up_left_chopstick();pick_up_right_chopstick();eat();put_down_right_chopstick();put_down_left_chopstick();// 吃完飯后,繼續思考人生、宇宙、萬物... }

    while(true) 代表整個是一個無限循環。在每個循環中,哲學家首先會開始思考,思考一段時間之后(這個時間長度可以是隨機的),他感到餓了,就準備開始吃飯。在吃飯之前必須先拿到左手的筷子,再拿到右手的筷子,然后才開始吃飯;吃完之后,先放回右手的筷子,再放回左手的筷子;由于這是個 while 循環,所以他就會繼續思考人生,開啟下一個循環。這就是整個過程。

    3.有死鎖和資源耗盡的風險

    這里存在什么風險呢?就是發生死鎖的風險。如下面的動畫所示:

    根據我們的邏輯規定,在拿起左手邊的筷子之后,下一步是去拿右手的筷子。大部分情況下,右邊的哲學家正在思考,所以當前哲學家的右手邊的筷子是空閑的,或者如果右邊的哲學家正在吃飯,那么當前的哲學家就等右邊的哲學家吃完飯并釋放筷子,于是當前哲學家就能拿到了他右手邊的筷子了。

    但是,如果每個哲學家都同時拿起左手的筷子,那么就形成了環形依賴,在這種特殊的情況下,每個人都拿著左手的筷子,都缺少右手的筷子,那么就沒有人可以開始吃飯了,自然也就沒有人會放下手中的筷子。這就陷入了死鎖,形成了一個相互等待的情況。

    4.代碼演示

    代碼如下所示:

    package com.netty.rpc.test.util;import java.lang.management.ManagementFactory; import java.lang.management.ThreadInfo; import java.lang.management.ThreadMXBean;public class DiningPhilosophers {public static class Philosopher implements Runnable {private Object leftChopstick;private Object rightChopstick;public Philosopher(Object leftChopstick, Object rightChopstick) {this.leftChopstick = leftChopstick;this.rightChopstick = rightChopstick;}@Overridepublic void run() {try {while (true) {doAction("思考人生、宇宙、萬物、靈魂...");synchronized (leftChopstick) {doAction("拿起左邊的筷子");synchronized (rightChopstick) {doAction("拿起右邊的筷子");doAction("吃飯");doAction("放下右邊的筷子");}doAction("放下左邊的筷子");}}} catch (InterruptedException e) {e.printStackTrace();}}private void doAction(String action) throws InterruptedException {System.out.println(Thread.currentThread().getName() + " " + action);Thread.sleep((long) (Math.random() * 10));}}public static void main(String[] args) throws InterruptedException {Philosopher[] philosophers = new Philosopher[5];Object[] chopsticks = new Object[philosophers.length];for (int i = 0; i < chopsticks.length; i++) {chopsticks[i] = new Object();}for (int i = 0; i < philosophers.length; i++) {Object leftChopstick = chopsticks[i];Object rightChopstick = chopsticks[(i + 1) % chopsticks.length];philosophers[i] = new Philosopher(rightChopstick, leftChopstick);new Thread(philosophers[i], "哲學家" + (i + 1) + "號").start();}Thread.sleep(1000 * 10);ThreadMXBean threadMXBean = ManagementFactory.getThreadMXBean();long[] deadlockedThreads = threadMXBean.findDeadlockedThreads();if(deadlockedThreads != null && deadlockedThreads.length > 0){for (int i= 0; i < deadlockedThreads.length; i++){long deadlockedThread = deadlockedThreads[i];ThreadInfo threadInfo = threadMXBean.getThreadInfo(deadlockedThread);System.out.println("線程id為"+threadInfo.getThreadId()+",線程名為" + threadInfo.getThreadName()+"的線程已經發生死鎖,需要的鎖正被線程"+threadInfo.getLockOwnerName()+"持有。");}}} }

    運行后截圖:

    哲學家 1、3、2、4、5 幾乎同時開始思考,然后,假設他們思考的時間比較相近,于是他們都在幾乎同一時刻想開始吃飯,都紛紛拿起左手的筷子,這時就陷入了死鎖狀態,沒有人可以拿到右手的筷子,也就沒有人可以吃飯,于是陷入了無窮等待,這就是經典的哲學家就餐問題。

    5.多種解決方案

    對于這個問題我們該如何解決呢?有多種解決方案,這里我們講講其中的幾種。前面我們講過,要想解決死鎖問題,只要破壞死鎖四個必要條件的任何一個都可以。

    1. 服務員檢查

    第一個解決方案就是引入服務員檢查機制。比如我們引入一個服務員,當每次哲學家要吃飯時,他需要先詢問服務員:我現在能否去拿筷子吃飯?此時,服務員先判斷他拿筷子有沒有發生死鎖的可能,假如有的話,服務員會說:現在不允許你吃飯。這是一種解決方案。

    2. 領導調節

    我們根據上一講的死鎖檢測和恢復策略,可以引入一個領導,這個領導進行定期巡視。如果他發現已經發生死鎖了,就會剝奪某一個哲學家的筷子,讓他放下。這樣一來,由于這個人的犧牲,其他的哲學家就都可以吃飯了。這也是一種解決方案。

    3. 改變一個哲學家拿筷子的順序

    我們還可以利用死鎖避免策略,那就是從邏輯上去避免死鎖的發生,比如改變其中一個哲學家拿筷子的順序。我們可以讓 4 個哲學家都先拿左邊的筷子再拿右邊的筷子,但是有一名哲學家與他們相反,他是先拿右邊的再拿左邊的,這樣一來就不會出現循環等待同一邊筷子的情況,也就不會發生死鎖了。

    死鎖解決
    我們把“改變一個哲學家拿筷子的順序”這件事情用代碼來寫一下,修改后的 main 方法如下:

    Philosopher[] philosophers = new Philosopher[5];Object[] chopsticks = new Object[philosophers.length];for (int i = 0; i < chopsticks.length; i++) {chopsticks[i] = new Object();}for (int i = 0; i < philosophers.length; i++) {Object leftChopstick = chopsticks[i];Object rightChopstick = chopsticks[(i + 1) % chopsticks.length];if (i == philosophers.length - 1){philosophers[i] = new Philosopher(rightChopstick, leftChopstick);}else{philosophers[i] = new Philosopher(leftChopstick, rightChopstick);} // philosophers[i] = new Philosopher(rightChopstick, leftChopstick);new Thread(philosophers[i], "哲學家" + (i + 1) + "號").start();}

    if (i == philosophers.length - 1) ,在這種情況下,我們給它傳入的筷子順序恰好相反,這樣一來,他拿筷子的順序也就相反了,他會先拿起右邊的筷子,再拿起左邊的筷子。那么這個程序運行的結果,是所有哲學家都可以正常地去進行思考和就餐了,并且不會發生死鎖。

    總結

    以上是生活随笔為你收集整理的什么叫死锁?死锁案例?死锁必须满足哪些条件?如何定位死锁问题?有哪些解决死锁策略?哲学家问题?的全部內容,希望文章能夠幫你解決所遇到的問題。

    如果覺得生活随笔網站內容還不錯,歡迎將生活随笔推薦給好友。

    主站蜘蛛池模板: 手机看片日韩福利 | 国产αv| 中国 免费 av| 久久极品视频 | 超薄肉色丝袜一二三 | 一区小视频| 国产主播中文字幕 | 男女啊啊啊 | 欧美性区| 五月天丁香久久 | 国产人妻一区二区 | 50部乳奶水在线播放 | 免费成人深夜在线观看 | 日韩精品中字 | 亚洲伦理在线播放 | 亚州色图欧美色图| 久久精品—区二区三区舞蹈 | 999av | 欧洲金发美女大战黑人 | 6699嫩草久久久精品影院 | 日本乱码视频 | 欧美 日韩 人妻 高清 中文 | 日韩午夜免费 | 国产在线观看无码免费视频 | 久久中文娱乐网 | a久久久久久 | 尤物网站在线播放 | 日本不卡一区 | 色成人免费网站 | 麻豆高清免费国产一区 | 女生扒开尿口 | 男操女免费网站 | 伊人久久综合视频 | 日韩午夜免费 | 国产粉嫩白浆 | 黄瓜视频色 | 欧美激情首页 | 亚洲在线电影 | 欧美日韩在线观看一区 | 99热都是精品 | 久草在现 | 国产一区二区三区四区五区美女 | 婷婷玖玖 | 久久久婷婷 | 大黑人交交护士xxxxhd | 中文字幕成人动漫 | 国产伦精品一区二区三区网站 | 女人十八岁毛片 | 久久久久无码国产精品不卡 | 欧美激情国产精品 | 色妞干网 | 天天爱天天爽 | 三级中文字幕在线 | 黄瓜视频在线免费观看 | 精品一区二区三区视频在线观看 | 流白浆视频 | 欧美tickle狂笑裸体vk | 51啪影院 | 久久精品10 | 天天插视频| 美女破处视频 | 精品欧美在线 | 亚洲精品一二三区 | 亚洲精品丝袜 | 国产三级三级在线观看 | 国产激情网址 | 色婷婷97| 91高清在线免费观看 | 高h视频在线观看 | 特黄大片又粗又大又暴 | 亚洲一区有码 | 四虎最新网址在线观看 | 日韩免费视频网站 | 日韩人妻无码精品久久久不卡 | 女人喷潮完整视频 | 医生强烈淫药h调教小说视频 | 亚洲av永久无码精品三区在线 | 亚洲每日在线 | 超能一家人电影免费喜剧在线观看 | 四虎激情 | 亚洲天堂视频在线观看 | 尤物在线 | 亚洲国产爱| 国产青青草在线 | 国产学生美女无遮拦高潮视频 | 成年人国产精品 | 裸体一区二区 | 五月天黄色小说 | 三浦惠理子aⅴ一二三区 | 日本黄色三级网站 | 国产传媒在线播放 | 国产精品久久久久久久成人午夜 | av男人的天堂av | 草草视频网站 | 在线国产播放 | 成人在线视频免费播放 | 成人爱爱免费视频 | 91高潮大合集爽到抽搐 | 134vcc影院免费观看 |