问题描述
- 哲学家进餐问题:5个哲学家共用一张圆桌,分别坐在周围的5张椅子上,在圆桌上有5个碗和5只筷子(注意是5只筷子,不是5双),碗和筷子交替排列。他们的生活方式是交替地进行思考(thinking)和进餐(eating)。平时,一个哲学家进行思考,饥饿时便试图取用其左右最靠近他的两只筷子,规定他必须先取左边的筷子,再取右边的筷子。只有在他拿到两只筷子时才能进餐。进餐完毕,放下筷子继续进行思考。假如5位哲学家同时饥饿,各自拿起左边的筷子时,再去拿各自右边的筷子,因为无筷子可拿而陷入无期限等待(死锁)。一种解决的办法是:至多只允许有4位哲学家同时去拿左边的筷子,最终能保证至少有一位哲学家能够拿到两只筷子,从而进餐。进餐完毕释放他用过的两只筷子,从而使更多的哲学家能够进餐。使用Java的多线程同步技术,实现上述解决方案。
主方法
package cn.learn.thread.ThreadState.practice; //测试 public class Test { public static void main(String[] args) { //五根筷子对象 Chopsticks[] chopsticks = new Chopsticks[5]; for (int i = 0; i <5 ; i++) { chopsticks[i] = new Chopsticks("---筷子"+i); } //创建五位哲学家进程,并传递其左右两边筷子 for (int i = 0; i < 5; i++) { Philosopher philosopher = new Philosopher("哲学家"+(i + 1)+": ",chopsticks[(i+1)%5],chopsticks[i]); philosopher.start(); } } }
筷子类
package cn.learn.thread.ThreadState.practice; /* 共享资源:筷子 */ public class Chopsticks { private String chopsticksName; public Chopsticks(String chopsticksName) { this.chopsticksName = chopsticksName; } public String getChopsticksName() { return chopsticksName; } public void setChopsticksName(String chopsticksName) { this.chopsticksName = chopsticksName; } }
哲学家进程
package cn.learn.thread.ThreadState.practice; import java.util.Random; public class Philosopher extends Thread { //左筷子 private Chopsticks leftChopsticks; //右筷子 private Chopsticks rightChopsticks; //静态引用类型保证同步时为同一把锁 private static Object obj = new Object(); private static int flag = 5; public Philosopher(String name, Chopsticks leftChopsticks, Chopsticks rightChopsticks) { //调用父方法给进程取名字 super(name); this.leftChopsticks = leftChopsticks; this.rightChopsticks = rightChopsticks; } @Override public void run() { while (true) { thinking(); takeChopsticks(); } } //思考 private void thinking() { //获取当前进程名称 String threadName = Thread.currentThread().getName(); Random random = new Random(); //睡眠,不释放锁 try { sleep(random.nextInt(10000)+1000); } catch (InterruptedException e) { e.printStackTrace(); } System.out.println(threadName + "思考中。。。"); } //拿筷子 public void takeChopsticks() { //让前四个哲学家先拿筷子 synchronized (obj) { //如果只剩一个哲学家让他等待 if (flag == 1) { try { obj.wait(); } catch (InterruptedException e) { e.printStackTrace(); } } //思考人数-- flag--; } //进程进来先给左筷子请求进入并上锁,再请求右筷子 synchronized (leftChopsticks) { //获取当前进程名称 String threadName = Thread.currentThread().getName(); //获取当前进程筷子 String chopsticksName = leftChopsticks.getChopsticksName(); //哲学家拿左筷子 System.out.println(threadName + "拿起一根左筷子" + chopsticksName); synchronized (rightChopsticks) { //获取当前进程筷子 chopsticksName = rightChopsticks.getChopsticksName(); System.out.println(threadName + "拿起一根右筷子" + chopsticksName + "开始吃饭!"); } //方法结束释放锁对象筷子 } //唤醒没有拿到筷子的哲学家 synchronized (obj) { obj.notify(); flag++; } } }
代码总结
- 五个哲学家在争抢筷子时,由系统调度,从而可能发生死锁,通过设置flag来解决使得有一名哲学家不能进餐,当有一个人进餐完成后,flag++,思考的人员增加;通过随机设置思考睡眠时间,可以达到五个哲学家可以随机有两个人同时吃饭。
来源:https://www.cnblogs.com/huxiaobai/p/11805447.html