哲学家就餐问题-Java语言实现死锁避免
哲学家就餐问题-Java语言实现死锁避免
我死锁预防是至少破坏死锁产生的四个必要条件之一,带来的问题就是系统资源利用率低且不符合开发习惯,而死锁避免不是事先釆取某种限制措施破坏死锁的必要条件,只是注意避免死锁的最终发生。
哲学家就餐问题
5 个沉默寡言的哲学家围坐在圆桌前,每人面前一盘意面。叉子放在哲学家之间的桌面上。(5 个哲学家,5 根筷子)
所有的哲学家都只会在思考和进餐两种行为间交替。哲学家只有同时拿到左边和右边的筷子才能吃到面,而同一根筷子在同一时间只能被一个哲学家使用。每个哲学家吃完面后都需要把筷子放回桌面以供其他哲学家吃面。只要条件允许,哲学家可以拿起左边或者右边的筷子,但在没有同时拿到左右筷子时不能进食。
产生死锁的四个必要条件:
(1) 互斥条件:一个资源每次只能被一个进程使用。
(2) 请求与保持条件:一个进程因请求资源而阻塞时,对已获得的资源保持不放。
(3) 不可剥夺条件:进程已获得的资源,在末使用完之前,不能强行剥夺。
(4) 环路等待条件:若干进程之间形成一种头尾相接的循环等待资源关系。
只要系统发生了死锁,这些条件必然成立,而只要上述条件之一不满足,就不会发生死锁。
解除死锁:从死锁进程处剥夺资源;终止部分或全部进程
Java语言实现死锁避免Demo
加锁前检查需要的资源是否足够,只有哲学家两边的筷子都没人用时同时拿起
import java.util.concurrent.locks.Condition;
import java.util.concurrent.locks.ReentrantLock;
class DiningPhilosophers {
//5根筷子的状态,0代表未使用,1代表已使用
public static int[] chopsticks = new int[5];
public static ReentrantLock lock = new ReentrantLock();
public static Condition condition = lock.newCondition();
public static void main(String[] args) {
for (int i = 0; i < 5; i++) {
new Thread(new Philosophers(i)).start();
}
}
static class Philosophers implements Runnable {
public int No;
public Philosophers(int no) {
No = no;
}
private void eat() {
System.out.println("哲学家 " + No + " is eating");
try {
Thread.currentThread().sleep(1500);
} catch (InterruptedException e) {
e.printStackTrace();
}
}
private void think() {
System.out.println("哲学家 " + No + " is thinking");
try {
Thread.currentThread().sleep(1500);
} catch (InterruptedException e) {
e.printStackTrace();
}
}
private void takeChopsticks() {
lock.lock();
//如果右边的筷子和左边的筷子都没有被使用
if (chopsticks[No] == 0 && chopsticks[(No + 4) % 5] == 0) {
chopsticks[No] = 1;
chopsticks[(No + 4) % 5] = 1;
} else {
try {
condition.await();
} catch (InterruptedException e) {
e.printStackTrace();
}
}
lock.unlock();
}
private void putdownChopsticks() {
lock.lock();
chopsticks[No] = 0;
chopsticks[(No + 4) % 5] = 0;
condition.signalAll();
lock.unlock();
}
@Override
public void run() {
while (true) {
this.think();
this.takeChopsticks();
this.eat();
this.putdownChopsticks();
}
}
}
}
/* 哲学家 0 is thinking
哲学家 4 is thinking
哲学家 1 is thinking
哲学家 3 is thinking
哲学家 2 is thinking
哲学家 0 is eating
哲学家 2 is eating
哲学家 2 is thinking
哲学家 0 is thinking
哲学家 1 is eating
哲学家 3 is eating
哲学家 4 is eating
哲学家 0 is eating
哲学家 3 is thinking
哲学家 2 is eating
哲学家 1 is thinking
……………………………… */
给锁添加时限:先拿起右边的筷子,再尝试拿左边的筷子,如果一段时间后依然没有拿到左边的筷子,则放下右边的筷子
import java.util.concurrent.locks.Condition;
import java.util.concurrent.locks.ReentrantLock;
class DiningPhilosophers2 {
public static ReentrantLock[] chopsticks = new ReentrantLock[5];
public static Condition[] conditions = new Condition[5];
public static void main(String[] args) {
for (int i = 0; i < 5; i++) {
chopsticks[i] = new ReentrantLock();
conditions[i] = chopsticks[i].newCondition();
}
for (int i = 0; i < 5; i++) {
new Thread(new Philosophers(i)).start();
}
}
static class Philosophers implements Runnable {
public int No;
public Philosophers(int no) {
No = no;
}
private void eat() {
System.out.println("哲学家 " + No + " is eating");
try {
Thread.currentThread().sleep(1500);
} catch (InterruptedException e) {
e.printStackTrace();
}
}
private void think() {
System.out.println("哲学家 " + No + " is thinking");
try {
Thread.currentThread().sleep(1000);
} catch (InterruptedException e) {
e.printStackTrace();
}
}
private void takeChopsticks() {
//是否获取了两个筷子
boolean acquire = false;
while (true) {
if (chopsticks[No].tryLock()) {
while (true) {
if (!chopsticks[(No + 4) % 5].tryLock()) {
chopsticks[No].unlock();
try {
Thread.currentThread().sleep(1000);
} catch (InterruptedException e) {
e.printStackTrace();
}
} else {
acquire = true;
}
break;
}
if (acquire) {
chopsticks[(No + 4) % 5].unlock();
chopsticks[No].unlock();
break;
}
}
}
}
private void putdownChopsticks() {
chopsticks[(No + 4) % 5].lock();
chopsticks[No].lock();
conditions[No].signalAll();
conditions[(No + 4) % 5].signalAll();
chopsticks[(No + 4) % 5].unlock();
chopsticks[No].unlock();
}
@Override
public void run() {
while (true) {
this.think();
this.takeChopsticks();
this.eat();
this.putdownChopsticks();
}
}
}
}
/* 哲学家 0 is thinking
哲学家 2 is thinking
哲学家 4 is thinking
哲学家 1 is thinking
哲学家 3 is thinking
哲学家 0 is eating
哲学家 2 is eating
哲学家 1 is eating
哲学家 3 is eating
哲学家 4 is eating
哲学家 0 is thinking
哲学家 1 is thinking
哲学家 2 is thinking
哲学家 0 is eating
哲学家 3 is thinking
哲学家 4 is thinking
哲学家 2 is eating
哲学家 1 is eating
哲学家 3 is eating
哲学家 0 is thinking
哲学家 2 is thinking
哲学家 1 is thinking
哲学家 4 is eating
哲学家 0 is eating
哲学家 3 is thinking
哲学家 1 is eating
哲学家 4 is thinking
哲学家 2 is eating
哲学家 3 is eating*/
哲学家就餐问题-Java语言实现死锁避免的更多相关文章
- 哲学家就餐问题 C语言实现
场景: 原版的故事里有五个哲学家(不过我们写的程序可以有N个哲学家),这些哲学家们只做两件事--思考和吃饭,他们思考的时候不需要任何共享资源,但是吃饭的时候就必须使用餐具,而餐桌上的餐具是有限的,原版 ...
- JAVA并发,经典死锁案例-哲学家就餐
转自:http://blog.csdn.net/tayanxunhua/article/details/38691005 死锁经典案例:哲学家就餐. 这个案例会导致死锁. 通过修改<Java编程 ...
- JAVA多线程学习--哲学家就餐问题
哲学家就餐问题是1965年由Dijkstra提出的一种线程同步的问题. 问题描述:一圆桌前坐着5位哲学家,两个人中间有一只筷子,桌子中央有面条.哲学家思考问题,当饿了的时候拿起左右两只筷子吃饭,必须拿 ...
- 进程同步——哲学家进餐问题Java实现
哲学家就餐问题是1965年由Dijkstra提出的一种线程同步的问题. 问题描述:一圆桌前坐着5位哲学家,两个人中间有一只筷子,桌子中央有面条.哲学家思考问题,当饿了的时候拿起左右两只筷子吃饭,必须拿 ...
- JAVA语言规范-线程和锁章节之同步、等待和通知
JAVA语言规范:线程和锁 1 同步 java编程语言提供了线程间通信的多种机制.这些方法中最基本的是同步化,此方法是使用监视器实现的.JAVA中每个对象与一个监视器相关联,一个线程可以加锁和解锁监视 ...
- 瘋耔java语言笔记
一◐ java概述 1.1 ...
- 基于JAVA语言的多线程技术
1.简介 多线程技术属于操作系统范围内的知识: 进程与线程 可以这么理解,一个应用程序就是一个进程,在一个进程中包含至少一个线程:进程就是线程的容器,真正工作.处理任务的是线程. 进程是操作系统分配资 ...
- linux下多线程互斥量实现生产者--消费者问题和哲学家就餐问题
生产者消费者问题,又有界缓冲区问题.两个进程共享一个一个公共的固定大小的缓冲区.其中一个是生产者,将信息放入缓冲区,另一个是消费者,从缓冲区中取信息. 问题的关键在于缓冲区已满,而此时生产者还想往其中 ...
- 已看1.熟练的使用Java语言进行面向对象程序设计,有良好的编程习惯,熟悉常用的Java API,包括集合框架、多线程(并发编程)、I/O(NIO)、Socket、JDBC、XML、反射等。[泛型]\
1.熟练的使用Java语言进行面向对象程序设计,有良好的编程习惯,熟悉常用的Java API,包括集合框架.多线程(并发编程).I/O(NIO).Socket.JDBC.XML.反射等.[泛型]\1* ...
随机推荐
- docker exec 参数详解
Usage: docker exec [OPTIONS] CONTAINER COMMAND [ARG...] Run a command in a running container Options ...
- Django的ORM如何执行group by 语句
问题描述: 使用Django的ORM建立了如下Model: class Book(models.Model): name = models.CharField(max_length=300) page ...
- oracle Group by 分组查询后,分页
------------恢复内容开始------------ 1.分页查询 select count(*) times,title from menulog group by title order ...
- 题解 P6892 [ICPC2014 WF]Baggage
解题思路 非常好的一道构造题. 在手动模拟几个样例(也许不止几个)之后呢. 就可以发现其实这些操作的开始以及最后几步是有相通之处的. 关于手动模拟的样例放在了文章末尾,需要的自取. 先考虑操作次数. ...
- Tomcat PUT方法任意写文件漏洞(CVE-2017-12615)
Apache Tomcat 7.0.0~7.0.79 直接发送以下数据包即可在Web根目录写入shell: PUT /1.jsp/ HTTP/1.1 Host: 192.168.49.2:8080 A ...
- mitmproxy第一次尝试-猿人学第九题
启动 mitmdump -s http_proxy.py -p 9000 替换js代码 # -*- coding: utf-8 -*- import re main_url = 'http://mat ...
- noi linux 2.0 体验
一.起因 下午,我打开 noi 官网准备报名 csp j/s,一看官网展板:"noi linux 2.0 发布" 我就兴奋了起来.(9 月 1 日起开始使用, 也就意味着 csp ...
- .Net Core如何优雅的实现中间件
在.Net Core的源码中,很多地方都有中间件的地方,Kestrel Server和Asp.net Core 等都用了中间件的设计,比如在Kestrel Server中,Http协议的1.0, 1. ...
- PDL语言/ 盒图N-S/ PAD图
PDL语言 伪码伪代码 基本语法 算法用Begin开始,以End结束(如果只表示中间部分的算法可以不要) 每一条指令,占一行.指令的结束不用任何符号 注释 用"//"表示 用Pri ...
- Linux从头学07:中断那么重要,它的本质到底是什么?
作 者:道哥,10+年的嵌入式开发老兵. 公众号:[IOT物联网小镇],专注于:C/C++.Linux操作系统.应用程序设计.物联网.单片机和嵌入式开发等领域. 公众号回复[书籍],获取 Linux. ...