JAVA并发,经典死锁案例-哲学家就餐
转自:http://blog.csdn.net/tayanxunhua/article/details/38691005
死锁经典案例:哲学家就餐。
这个案例会导致死锁。
通过修改《Java编程思想4》一书中的案例,来做实验,代码更易理解,结果也相对容易控制。
附代码:
筷子类:
package com.tyxh.ch21.c6;
public class Chopstick {
private boolean taken = false;//判断是此筷子是否被拿起
public synchronized void take() throws InterruptedException {
while(taken) {
//如果已被拿起,则等待
wait();
}
//如果没有被拿起,则可以被拿起,并设置taken为true
taken = true;
}
public synchronized void drop() {
//放下筷子之后设置taken为false,并通知其他哲学家
taken = false;
notifyAll();
}
}
哲学家类:
package com.tyxh.ch21.c6; import java.util.Random;
import java.util.concurrent.TimeUnit; public class Philosopher implements Runnable {
private Chopstick left;//左筷子
private Chopstick right;//右筷子 private final int id;//哲学家编号
private final int ponderFactor;//根据这个属性设置思考时间 private Random rand = new Random(47);
private void pause() throws InterruptedException {
if(ponderFactor == 0) {
return;
}
TimeUnit.MILLISECONDS.sleep(rand.nextInt(ponderFactor *250));
} public Philosopher(Chopstick left, Chopstick right, int ident, int ponder) {
this.left = left;
this.right = right;
this.id = ident;
this.ponderFactor = ponder;
} public void run() {
try{
while(!Thread.interrupted()) {
System.out.println(this + " " + "thinking");
pause();
right.take();
System.out.println(this + " " + "拿右筷子");
left.take();
System.out.println(this + " " + "拿左筷子");
pause();
System.out.println(this + " " + "吃");
right.drop();
System.out.println(this + " " + "放下右筷子");
left.drop();
System.out.println(this + " " + "放下左筷子");
}
}catch(InterruptedException e) {
System.out.println(this + " 退出 ");
}
} public String toString() {
return "Phiosopher : " + id;
}
}
测试类:
package com.tyxh.ch21.c6; import java.util.concurrent.ExecutorService;
import java.util.concurrent.Executors;
import java.util.concurrent.TimeUnit; public class DeadlockingDiningPhilosophers {
public static void main(String[] args) throws InterruptedException {
int ponder = 5;
if(args.length > 0) {
ponder = Integer.parseInt(args[0]);
}
int size = 5;
if(args.length > 1) {
size = Integer.parseInt(args[1]);
}
ExecutorService exec = Executors.newCachedThreadPool();
Chopstick[] stick = new Chopstick[size]; for(int i = 0; i < size; i++) {
stick[i] = new Chopstick();
} for(int i = 0; i < size; i++) {
Philosopher p = new Philosopher(stick[i], stick[(i+1)%size], i, ponder);
exec.execute(p);
} TimeUnit.SECONDS.sleep(3);
exec.shutdownNow(); }
}
可以通过命令行参数调整ponder因子设置哲学家思考时间,也可以设置筷子及哲学家的数量size。
死锁产生的四个必要条件。
1>互斥使用,即当资源被一个线程使用(占有)时,别的线程不能使用
2>不可抢占,资源请求者不能强制从资源占有者手中夺取资源,资源只能由资源占有者主动释放。
3>请求和保持,即当资源请求者在请求其他的资源的同时保持对原有资源的战友。
4>循环等待,即存在一个等待队列:P1占有P2的资源,P2占有P3的资源,P3占有P1的资源。这样就形成了一个等待环路。
当上述四个条件都成立的时候,便形成死锁。当然,死锁的情况下如果打破上述任何一个条件,便可让死锁消失。
这里仅给出书中处理此死锁的解决方案(破坏第四种条件):
方案是:
前面哲学家拿筷子的顺序都是先拿右,再拿左,但最后一个哲学家拿筷子的顺序是先拿左,再拿右,就可以通过阻止循环等待这个死锁的条件来阻止死锁发生。
即将代码:
for(int i = 0; i < size; i++) {
Philosopher p = new Philosopher(stick[i], stick[(i+1)%size], i, ponder);
exec.execute(p);
}
修改为:
for(int i = 0; i < size; i++) {
if(i < size - 1) {
Philosopher p = new Philosopher(stick[i], stick[(i+1)%size], i, ponder);
exec.execute(p);
}else {
Philosopher p = new Philosopher(stick[0], stick[i], i, ponder);
exec.execute(p);
}
}
JAVA并发,经典死锁案例-哲学家就餐的更多相关文章
- 哲学家就餐问题-Java语言实现死锁避免
哲学家就餐问题-Java语言实现死锁避免 我死锁预防是至少破坏死锁产生的四个必要条件之一,带来的问题就是系统资源利用率低且不符合开发习惯,而死锁避免不是事先釆取某种限制措施破坏死锁的必要条件,只是注意 ...
- Java并发案例01---多线程之死锁
多线程之死锁案例一 package example; /** * 模拟死锁 * @author maple * */ public class DeadLock { public int flag = ...
- Java并发编程(十)死锁
哲学家进餐问题 并发执行带来的最棘手的问题莫过于死锁了,死锁问题中最经典的案例就是哲学家进餐问题:5个哲学家坐在一个桌子上,桌子上有5根筷子,每个哲学家的左手边和右手边各有一根筷子.示意图如下: 哲学 ...
- Java并发编程实战(4)- 死锁
在这篇文章中,我们主要讨论一下死锁及其解决办法. 目录 概述 死锁案例 死锁的原因和预防 破坏占用且等待条件 破坏不可抢占条件 破坏循环条件 使用等待-通知机制 Java中的等待-通知机制 条件曾经满 ...
- 【Java并发基础】死锁
前言 我们使用加锁机制来保证线程安全,但是如果过度地使用加锁,则可能会导致死锁.下面将介绍关于死锁的相关知识以及我们在编写程序时如何预防死锁. 什么是死锁 学习操作系统时,给出死锁的定义为两个或两个以 ...
- 【Java并发基础】使用“等待—通知”机制优化死锁中占用且等待解决方案
前言 在前篇介绍死锁的文章中,我们破坏等待占用且等待条件时,用了一个死循环来获取两个账本对象. // 一次性申请转出账户和转入账户,直到成功 while(!actr.apply(this, targe ...
- JAVA多线程学习--哲学家就餐问题
哲学家就餐问题是1965年由Dijkstra提出的一种线程同步的问题. 问题描述:一圆桌前坐着5位哲学家,两个人中间有一只筷子,桌子中央有面条.哲学家思考问题,当饿了的时候拿起左右两只筷子吃饭,必须拿 ...
- Java并发编程原理与实战十一:锁重入&自旋锁&死锁
一.锁重入 package com.roocon.thread.t6; public class Demo { /* 当第一个线程A拿到当前实例锁后,进入a方法,那么,线程A还能拿到被当前实例所加锁的 ...
- 17、Java并发性和多线程-避免死锁
以下内容转自http://ifeve.com/deadlock-prevention/: 在有些情况下死锁是可以避免的.本文将展示三种用于避免死锁的技术: 加锁顺序 当多个线程需要相同的一些锁,但是按 ...
随机推荐
- PHP基础示例:用正则表达式修改配置信息
各php工作原理图: 以下是扯代码时间: <?php //配置文件信息 define("HOST","localhost"); //主机名 define( ...
- 精读《javascript高级程序设计》笔记一——基本概念
语法 严格模式 启用严格模式,在脚本顶部或函数内部上方添加"use strict";语句. 数据类型 typeof typeof返回undifined,boolean,number ...
- 线程中的异常处理——怪不得所有的语句,都用try catch包的严严实实,甚至每个小步骤还要单独包起来
答案是:在线程中出现没处理的异常时,线程会自动终止. 以前刚看到别人的代码时候,十分惊讶,try catch几乎成了最主要的语句了,还以为是因为代码风格,或者更严谨一些的原因.到今天才明白,原来还不是 ...
- 接口返回json
use Mojolicious::Lite; use JSON qw/encode_json decode_json/; # /foo?user=sri get '/api' => sub { ...
- Android自定义View研究--View中的原点坐标和XML中布局自定义View时View触摸原点问题
这里只做个汇总~.~独一无二 文章出处:http://blog.csdn.net/djy1992/article/details/9715047 Android自定义View研究--View中的原点坐 ...
- [虚拟化/云][全栈demo] 为qemu增加一个PCI的watchdog外设(一)
目的: 结合现在比较流行的技术,通过一个demo 展示一个全栈式设计的各种技能. 一个全栈式的工程师,应该能设计通过verilog/VHDL做logical设计.能写内核驱动,能架站. 要熟悉veri ...
- 轻奢当道业绩逆势增长 Kate Spade联手韩国衣恋开拓中国市场_商场报道_中国时尚品牌网
轻奢当道业绩逆势增长 Kate Spade联手韩国衣恋开拓中国市场_商场报道_中国时尚品牌网 轻奢当道业绩逆势增长 Kate Spade联手韩国衣恋开拓中国市场
- mongoose的populate的使用方法;
LotteryReceiveRecord.find({"lottery":req.params.id}).populate("user lottery").ex ...
- Pig Latin儿童黑话(java)
●假设单词以辅音字母開始,将词首的辅音字母字符串(第一个元音字母前的全部字母)从单词的开头移动到末尾,然后加上后缀ay,这样就形成了它的pig latin. ●假设单词以元音字母開始,仅仅须要 ...
- ASP.NET实现列表页连接查询 拼接sql语句 绑定grivdView
ASP.NET实现列表页连接查询 拼接sql语句 如图效果: 基本需求:1.当页面第一次加载的时候默认查询一个月时间(或者说是登陆者所属权限的所有数据)的数据绑定到gridView 2.添加查询条件时 ...