文章目录

  • 哲学家就餐
  • 问题描述
  • 流程
  • 思考
  • 代码演示
  • 解决哲学家就餐问题的4种方案
  • 改变一个哲学家拿叉子的顺序(代码演示)

在【死锁】这一篇文章中,我们学习了死锁相关的理论知识,本篇文章来看看死锁案例——哲学家就餐问题,这篇文章主要来讨论就餐问题的死锁和多种死锁修复的方法。

哲学家就餐

问题描述

看上图,有五位哲学家,面前都有一个盘子,盘子左边和右边都有一根筷子,他们在吃面之前需要先拿起左边的筷子再拿起右边的筷子,有了一双筷子就可以吃面了。

流程

  • 先拿起左手的筷子
  • 然后拿起右手的筷子
  • 如果筷子被人使用了,那就等别人用完
  • 吃完后,把筷子放回原位

思考

上面流程有死锁和资源耗尽的风险

  • 死锁:每个哲学家都拿着左手的筷子,永远在等右边的筷子(或者相反)

代码演示

哲学家:每个哲学家重复做的事就是:思考,拿筷子吃面

public 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("放下左边筷子...");}}} 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 class DiningPhilosophers {public static void main(String[] args) {//五个哲学家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(leftChopstick, rightChopstick);new Thread(philosophers[i], "哲学家" + (i + 1) + "号").start();}}
}

打印结果:可以看到,五个哲学家最后都拿起了左边筷子,都在等右边筷子,就发生了死锁。

...
哲学家3号 拿起左边筷子...<
哲学家2号 思考中...
哲学家1号 拿起右边筷子,然后开始吃面...
哲学家1号 放下右边筷子...
哲学家1号 放下左边筷子...
哲学家2号 拿起左边筷子...<
哲学家5号 拿起右边筷子,然后开始吃面...
哲学家1号 思考中...
哲学家5号 放下右边筷子...
哲学家5号 放下左边筷子...
哲学家1号 拿起左边筷子...<
哲学家5号 思考中...
哲学家4号 拿起右边筷子,然后开始吃面...
哲学家4号 放下右边筷子...
哲学家4号 放下左边筷子...
哲学家5号 拿起左边筷子...<
哲学家4号 思考中...
哲学家4号 拿起左边筷子...<

解决哲学家就餐问题的4种方案

  1. 服务员检查(避免策略):引入一个服务员协调,就是说当哲学家要拿起筷子的时候,先询问服务员能否拿起,服务员就会检查拿起筷子是否会有死锁的发生,不会的话就允许哲学家拿起筷子,相反如果可能会发生死锁就不让哲学家拿起筷子。
  2. 改变一个哲学家拿叉子的顺序(避免策略):因为要发生死锁,一定是所有哲学家都拿起了左边的筷子,发生了死锁环路,但是假如有个哲学家不按照顺时针拿的话,就是说先拿右边筷子,这样就永远不会发生都在等右边筷子的死锁环路了。
  3. 餐票(避免策略):就是说每个人吃饭前都要先拿到餐票才能拿筷子吃面,餐票总共只有4张,也就是说一定有个人能拿到一双筷子吃面,但是吃完餐票也要还回去。
  4. 领导调节(检测与恢复策略):并不是不让你发生死锁,而是等你死锁了,领导检测到了死锁发生(五个人都拿起了左边的筷子),就会命令其中一个人放下筷子,让别人先吃。

改变一个哲学家拿叉子的顺序(代码演示)

public class DiningPhilosophers {public static void main(String[] args) {//五个哲学家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);}new Thread(philosophers[i], "哲学家" + (i + 1) + "号").start();}}
}

打印结果:程序会一直运行下去,不再发生死锁。

哲学家1号 思考中...
哲学家3号 思考中...
哲学家4号 思考中...
哲学家2号 思考中...
哲学家5号 思考中...
哲学家4号 拿起左边筷子...
哲学家2号 拿起左边筷子...
哲学家4号 拿起右边筷子,然后开始吃面...
哲学家2号 拿起右边筷子,然后开始吃面...
哲学家5号 拿起左边筷子...
哲学家4号 放下右边筷子...
哲学家4号 放下左边筷子...
哲学家5号 拿起右边筷子,然后开始吃面...
哲学家4号 思考中...
哲学家5号 放下右边筷子...
哲学家2号 放下右边筷子...
...

笔记来源:慕课网悟空老师视频《Java并发核心知识体系精讲》

死锁——哲学家就餐问题相关推荐

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

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

  2. 哲学家就餐与死锁问题,死锁产生的条件以及解决方案

    请结合经典案例-哲学家就餐,来谈谈你对死锁的理解,以及怎么预防和解除死锁? 哲学家就餐 描述:在一张圆桌上,有n个哲学家,n支筷子,他们的生活方式只是交替地进行思考和进餐,饥饿时便试图取其左.右最靠近 ...

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

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

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

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

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

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

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

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

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

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

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

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

  9. 哲学家就餐问题python_哲学家就餐问题与死锁

    问题描述 哲学家就餐问题(Dining philosophers problem)是在计算机科学中的一个经典问题,用来演示在并发计算中多线程同步(Synchronization)时产生的问题. 哲学家 ...

  10. 多线程“死锁”之“哲学家就餐”代码实现

    死锁:就是两个或者两个以上的线程相互占用对方的需要的资源,而不进行释放,导致彼此都在等待对方释放资源,产生了无限制的等待的现象. "哲学家就餐"的问题不在赘述,可以自行百度或者Go ...

最新文章

  1. 院士领衔,大咖云集!航天智慧物流单项赛决赛倒计时2天!
  2. 将CAGradientLayer当做mask使用
  3. python 创建子类_python创建子类的方法分析
  4. Linux视频 pad,Wine 1.9.10 发布下载, 改善视频输出
  5. 第二章附加例题:委托类型
  6. Unity之如何使用夜神模拟器logcat
  7. php读取西门子plc_第三方设备如何读取PLC数据
  8. 真么找计算机用户密码,如何查找电脑的用户名和密码
  9. WPS-JS宏开发-基础知识-01-初识
  10. SpringBoot导出txt文件
  11. BZOJ 4816(莫比乌斯反演
  12. QGIS 导入图层到 PostGIS “导入某些图层失败! 图层“public“.‘xxxx‘载入失败 “
  13. ATM(异步传输模式)
  14. 【086】微博切九图-图片在线切分四份或九份
  15. Win10联想电脑连不上wifi解决方法
  16. Flask教程(二十)flask-apscheduler
  17. 蓝桥杯-算法训练 印章
  18. 正则表达式与遇到的问题
  19. 嵌入式是什么意思?嵌入式是干什么的?
  20. 达梦数据库全量数据恢复还原流程

热门文章

  1. SNN系列|神经元模型篇(2) Izhikevich
  2. Google Code 中使用svn工具说明
  3. 费尔防火墙源代码阅读
  4. 开发计算机新功能,Tablet PC 开发的新增功能
  5. 紫光输入法linux,紫光拼音输入法
  6. Msm8960(APQ8064)平台的MSM-AOSP-kitkat编译适配(1):基础知识
  7. 全自动共享软件破解器4.8
  8. 如何在计算机安装WPS,windowsxp系统电脑怎样安装wps插件
  9. 智慧城市顶层设计规划方案
  10. java学生奖学金管理系统_java毕业设计_springboot框架的高校学生奖学金评定系统...