请结合经典案例-哲学家就餐,来谈谈你对死锁的理解,以及怎么预防和解除死锁?

哲学家就餐

描述:在一张圆桌上,有n个哲学家,n支筷子,他们的生活方式只是交替地进行思考和进餐,饥饿时便试图取其左、右最靠近他的筷子,只有在他拿到两支筷子时才能进餐,进餐完毕,放下筷子又继续思考。

根据描述,实现代码如下:

import java.util.Random;
import java.util.concurrent.ExecutorService;
import java.util.concurrent.Executors;
import java.util.concurrent.TimeUnit;public class Question17 {public static void main(String[] args) {ExecutorService exec = Executors.newCachedThreadPool();int sum = 5;Chopstick[] chopsticks = new Chopstick[sum];for (int i = 0; i < sum; i++) {chopsticks[i] = new Chopstick(i);}for (int j = 0; j < sum; j++) {exec.execute(new Philosopher(chopsticks[j], chopsticks[(j + 1) % sum], j));}}
}// 筷子
class Chopstick {// 筷子位置  private int id;// 状态private boolean isUsed = false;public Chopstick(int id) {this.id = id;}// 拿取public synchronized void take() throws InterruptedException {while (isUsed) {wait();}System.err.println(this + " 被使用");isUsed = true;}// 放下public synchronized void drop() {isUsed = false;System.err.println(this + " 被放下");notifyAll();}@Overridepublic String toString() {return "筷子[" + id + "]";}
}// 哲学家
class Philosopher implements Runnable {private Chopstick left;private Chopstick right;private int id;private Random rand = new Random();public Philosopher(Chopstick left, Chopstick right, int id) {this.left = left;this.right = right;this.id = id;}@Overridepublic void run() {while (!Thread.interrupted()) {try {think();System.out.println(this + " 想吃饭!");eat();} catch (InterruptedException e) {System.err.println(this + " InterruptedException");}}}// 思考private void think() throws InterruptedException {System.out.println(this + " 思考...");TimeUnit.MILLISECONDS.sleep(rand.nextInt(1) * 100);}// 吃饭private void eat() throws InterruptedException {left.take();right.take();System.out.println(this + " 正在吃饭...");TimeUnit.MILLISECONDS.sleep(rand.nextInt(2) * 100);left.drop();right.drop();}@Overridepublic String toString() {return "哲学家[" + id + "]";}
}

通过运行结果,我们可以发现,到最后,没有一个哲学家能过同时获取两只筷子吃饭。

二、为什么会产生死锁

死锁问题被认为是线程/进程间切换消耗系统性能的一种极端情况。在死锁时,线程/进程间相互等待资源,而又不释放自身的资源,导致无穷无尽的等待,其结果是任务永远无法执行完成。哲学家问题便是线程资源竞争导致的死锁现象,在程序运行一段时间后,程序所处的状态是n位哲学家(n个线程)都各自获取了一只筷子的状态,此时所有哲学家都想获取第二只筷子去吃饭,但是共享资源n只筷子已经都被n位哲学家握在手里了,彼此想要的筷子都在其他哲学家手中,又没有机制能让任何哲学家放弃握在手中的筷子,从而照成了所有哲学家(所有线程)都在等待其他人手中资源的死锁问题。

产生死锁的四个必要条件: 

  1. 互斥条件:一个资源每次只能被一个线程/进程使用。
  2. 请求与保持条件:一个线程/进程因请求资源而阻塞时,对已获得的资源保持不放。
  3. 不剥夺条件:线程/进程已获得的资源,在未使用完之前,不能强行剥夺。
  4. 循环等待条件:若干线程/进程之间形成一种头尾相接的循环等待资源关系。

三、死锁的解除与预防

一般解决死锁的途径分为死锁的预防,避免,检测与恢复这三种。

死锁的预防是要求线程/进程申请资源时遵循某种协议,从而打破产生死锁的四个必要条件中的一个或几个,保证系统不会进入死锁状态。

死锁的避免不限制线程/进程有关申请资源的命令,而是对线程/进程所发出的每一个申请资源命令加以动态地检查,并根据检查结果决定是否进行资源分配。

死锁检测与恢复是指系统设有专门的机构,当死锁发生时,该机构能够检测到死锁发生的位置和原因,并能通过外力破坏死锁发生的必要条件,从而使得并发进程从死锁状态中恢复出来。

对于java程序来说,产生死锁时,我们可以用jvisualvm/jstack来分析程序产生的死锁原因,根治死锁问题。

哲学家就餐与死锁问题,死锁产生的条件以及解决方案相关推荐

  1. 哲学家吃饭问题-对线程死锁的理解

    哲学家就餐问题-对线程死锁的理解 两个线程的死锁问题: 线程1 首先占有对象1,接着试图占有对象2 线程2 首先占有对象2,接着试图占有对象1 线程1 等待线程2释放对象2 与此同时,线程2等待线程1 ...

  2. 死锁、活锁、饥饿定位死锁解决死锁

    文章目录 1. 死锁 2. 定位死锁 2.1 jstack工具使用 2.2 jconsole工具使用: 3. 解决死锁 3.1 哲学家就餐问题 4. 活锁 4.1 活锁原因 4.2 活锁解决 5. 饥 ...

  3. 哲学家就餐问题--信号量和互斥量预防死锁

    哲学家就餐问题可以采取预防死锁的方案,就是使用互斥量和信号量锁定资源. 互斥量: 对资源进行锁定的意思就是说,当一个哲学家使用叉子的时候,他首先要先把叉子锁定,然后,拿起来.这个时候如果别的哲学家也来 ...

  4. 哲学家就餐(避免死锁)(多进程版)

    哲学家就餐(避免死锁)(多进程版) 哲学家就餐利用信号量在多进程之间实现 下面展示一些代码片段 #include <stdio.h> #include <unistd.h> # ...

  5. 哲学家就餐问题(如何避免死锁)(多线程版)

    哲学家就餐问题 多线程编程中,常常会遇到线程间访问共享资源的问题,如果处理不当则会发生死锁,某一个线程可能永远访问不到共享资源. 为了避免死锁的发生,提出哲学家就餐问题. 下面展示一些代码片段 #in ...

  6. Java多线程学习四十二:有哪些解决死锁问题的策略和哲学家就餐问题

    线上发生死锁应该怎么办 如果线上环境发生了死锁,那么其实不良后果就已经造成了,修复死锁的最好时机在于"防患于未然",而不是事后补救.就好比发生火灾时,一旦着了大火,想要不造成损失去 ...

  7. Thinking in Java---从哲学家就餐问题看死锁现象

    我们知道一个对象可以有synchronized方法或其他形式的加锁机制来防止别的线程在互斥还没释放的时候就访问这个对象.而且我们知道线程是会变成阻塞状态的(挂起),所以有时候就会发生死锁的情况:某个任 ...

  8. 哲学家就餐问题的三种避免死锁的解法(PV操作)

    哲学家就餐问题的三种避免死锁的解法(PV操作) 方案一:最多允许有四位哲学家同时去拿左边的筷子,然后再拿右边的筷子,最终保证至少有一位哲学家能够进餐,并在就餐完毕时同时释放他用过的两只筷子,从而使更多 ...

  9. 死锁和饥饿-哲学家就餐问题

    哲学家就餐问题 背景: 假设5位哲学家住在一起(可以推广到n),每天生活就是思考和吃饭,每位哲学家需要2把叉子来吃意大利面. 就餐安排: 一张圆桌,5个板凳,5个盘子,5把叉子,每个想吃饭的哲学家做到 ...

最新文章

  1. 003_ZooKeeper服务端集群搭建
  2. 存储器的保护(二)——《x86汇编语言:从实模式到保护模式》读书笔记19
  3. Jmeter-逻辑控制器
  4. tomcat,eclipse,sts绿色运行
  5. LeetCode 134 Gas Station
  6. mysql管理数据 并上传至云端_西部数码网站管理助手创建、导入恢复、导出备份mysql数据库...
  7. 关灯游戏 Lights out (二)(首行枚举+位运算,搜索全部解)
  8. 2017博鳌亚洲青年论坛(香港)顺利召开 中国发展人工智能优势在哪?
  9. Java零基础入门(五)
  10. 域名备案和网站备案是一个意思吗?
  11. java算法训练 调和数列问题
  12. 微信小程序注册开发流程详解
  13. 论文阅读笔记《Few-Shot Learning with Global Class Representations》
  14. 阿里云服务器SSL不可用
  15. 谈一谈mmkv的使用
  16. 51单片机:数码管(静态+动态)
  17. vue.js动态设置VueComponent高度遇到的问题
  18. 为什么oracle依旧是很多大公司数据库首选?
  19. 思科、华为交换机err-disable的相关排查解决
  20. JAVA五子棋单机版

热门文章

  1. php 如何将字体转为gb,利用php怎么将utf-8与GB2312相互转换
  2. Python 定时任务框架 APScheduler
  3. 多索引表 (8)表操作
  4. 比特币钱包(2) BIP32 HD钱包之生成子密钥
  5. 创新实训个人记录:metric k-center
  6. 数据结构--插入排序
  7. Windows服务器版本简介
  8. [JAVA基础类库] String类 ○ StringBuffer类 ○ StringBuilder类
  9. 【django】配置Jinja2模板引擎【2】
  10. [Issue Fixed]-执行脚本时出现invalid option错误