哲学家就餐问题-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* ...
随机推荐
- jvm源码解读--02 Array<u1>* tags = MetadataFactory::new_writeable_array<u1>(loader_data, length, 0, CHECK_NULL); 函数引入的jvm内存分配解析
current路径: #0 Array<unsigned char>::operator new (size=8, loader_data=0x7fd4c802e868, length=8 ...
- nexus 私服 设置本公司代理 记录
index成功
- GoAhead 远程命令执行漏洞(CVE-2017-17562)
poc地址 https://github.com/ivanitlearning/CVE-2017-17562 执行 msfvenom -a x64 --platform Linux -p linux/ ...
- Dapr 客户端 搭配 WebApiClientCore 玩耍服务调用
使用Dapr 客户端 处理服务调用,需要遵循的他的模式,通常代码是这个样子的: var client = DaprClient.CreateInvokeHttpClient(appId: " ...
- 探索HashMap源码 一行一行解析 jdk1.7版本
今天我们来说一说,HashMap的源码到底是个什么? 面试大厂这方面一定会经常问到,很重要的.以jdk1.7 为标准 先带着大家过一遍 是由数组.链表组成 , 数组的优点是:每个元素有对应下标, ...
- GooseFS助力大数据业务数倍提升计算能力
前言 GooseFS是由腾讯云推出的一款分布式缓存方案,主要针对包括需要缓存加速的数据湖业务场景,提供基于对象存储COS服务的近计算端数据加速层. GooseFS 基于开源大数据缓存方案 Alluxi ...
- 【LeetCode】738. 单调递增的数字
738. 单调递增的数字 知识点:字符串:贪心 题目描述 给定一个非负整数 N,找出小于或等于 N 的最大的整数,同时这个整数需要满足其各个位数上的数字是单调递增. (当且仅当每个相邻位数上的数字 x ...
- 【笔记】KNN之超参数
超参数 超参数 很多时候,对于算法来说,关于这个传入的参数,传什么样的值是最好的? 这就涉及到了机器学习领域的超参数 超参数简单来说就是在我们运行机器学习之前用来指定的那个参数,就是在算法运行前需要决 ...
- 有关SQL注入的一些小知识点
1.判断注入点: 本质原理是找一个需要后台处理后,提交给数据库的点,我理解为用户可以控制并输入后台数据库的变量,比如我们DVWA SQL injection 的ID ,我们可以通过闭合单引号,#注释 ...
- SpringBoot中Jackson的过滤使用
在接口的返回对象中,可能会有一些属性为null或者需要禁止某些字段返回给客户端. 在SpringBoot中可使用内置了Jackson实现这个需求 1. 过滤为null字段 在实体类中使用@JsonIn ...