转自: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并发,经典死锁案例-哲学家就餐的更多相关文章

  1. 哲学家就餐问题-Java语言实现死锁避免

    哲学家就餐问题-Java语言实现死锁避免 我死锁预防是至少破坏死锁产生的四个必要条件之一,带来的问题就是系统资源利用率低且不符合开发习惯,而死锁避免不是事先釆取某种限制措施破坏死锁的必要条件,只是注意 ...

  2. Java并发案例01---多线程之死锁

    多线程之死锁案例一 package example; /** * 模拟死锁 * @author maple * */ public class DeadLock { public int flag = ...

  3. Java并发编程(十)死锁

    哲学家进餐问题 并发执行带来的最棘手的问题莫过于死锁了,死锁问题中最经典的案例就是哲学家进餐问题:5个哲学家坐在一个桌子上,桌子上有5根筷子,每个哲学家的左手边和右手边各有一根筷子.示意图如下: 哲学 ...

  4. Java并发编程实战(4)- 死锁

    在这篇文章中,我们主要讨论一下死锁及其解决办法. 目录 概述 死锁案例 死锁的原因和预防 破坏占用且等待条件 破坏不可抢占条件 破坏循环条件 使用等待-通知机制 Java中的等待-通知机制 条件曾经满 ...

  5. 【Java并发基础】死锁

    前言 我们使用加锁机制来保证线程安全,但是如果过度地使用加锁,则可能会导致死锁.下面将介绍关于死锁的相关知识以及我们在编写程序时如何预防死锁. 什么是死锁 学习操作系统时,给出死锁的定义为两个或两个以 ...

  6. 【Java并发基础】使用“等待—通知”机制优化死锁中占用且等待解决方案

    前言 在前篇介绍死锁的文章中,我们破坏等待占用且等待条件时,用了一个死循环来获取两个账本对象. // 一次性申请转出账户和转入账户,直到成功 while(!actr.apply(this, targe ...

  7. JAVA多线程学习--哲学家就餐问题

    哲学家就餐问题是1965年由Dijkstra提出的一种线程同步的问题. 问题描述:一圆桌前坐着5位哲学家,两个人中间有一只筷子,桌子中央有面条.哲学家思考问题,当饿了的时候拿起左右两只筷子吃饭,必须拿 ...

  8. Java并发编程原理与实战十一:锁重入&自旋锁&死锁

    一.锁重入 package com.roocon.thread.t6; public class Demo { /* 当第一个线程A拿到当前实例锁后,进入a方法,那么,线程A还能拿到被当前实例所加锁的 ...

  9. 17、Java并发性和多线程-避免死锁

    以下内容转自http://ifeve.com/deadlock-prevention/: 在有些情况下死锁是可以避免的.本文将展示三种用于避免死锁的技术: 加锁顺序 当多个线程需要相同的一些锁,但是按 ...

随机推荐

  1. TreeSet类的排序问题

     http://www.cnblogs.com/lixiaolun/archive/2012/12/25/2832775.html TreeSet支持两种排序方法:自然排序和定制排序.TreeSet默 ...

  2. C++ 数据结构学习二(单链表)

    模板类 //LinkList.h 单链表#ifndef LINK_LIST_HXX#define LINK_LIST_HXX#include <iostream>using namespa ...

  3. lightoj 1038 Race to 1 Again

    题意:给一个数,用这个数的因数除以这个数,直到为1时,求除的次数的期望. 设一个数的约数有M个,E[n] = (E[a[1]]+1)/M+(E[a[2]]+1)/M+...+(E[a[M]]+1)/M ...

  4. [C#参考]属性

    属性和字段不同,属性是一个函数成员:它提供灵活的机制来读取.编写或计算某个私有字段的值. 可以像使用公共数据成员一样使用属性,但实际上它们是称作“访问器”的特殊方法. 这使得可以轻松访问数据,此外还有 ...

  5. leetcode Combination Sum II python

    Given a collection of candidate numbers (C) and a target number (T), find all unique combinations in ...

  6. springFramework 源码学习之源码下载与编译

    1.源码下载 Spring已经将源码从svn迁移到了git.对于习惯了svn的人来说依然可以svn checkout,最好checkout到英文路径下,本人中文路径编译不过,具体原因不明,路径: ht ...

  7. [置顶] woff格式字体怎么打开和编辑?

    如题! woff百度百科:http://baike.baidu.com/link?url=toS7yqpN9VlEcO2GOEp5JEA9-TeaZgIdVqTOv7iHshsNvk-V8HtxEY0 ...

  8. 在IE6/7下表格td标签没有内容时不显示边框?

    有以下几种方法: 1.在单元格中加入一个空格.这样: <td> </td> 2.直接在table里这样写:<table border="0" cell ...

  9. head first 设计模式读书笔记 之 策略模式

    作为一个php开发者,深知曾经很多程序员都鄙视php,为什么呢?因为他们认为php的语法是dirty的,并且由于开发者水平参差不齐导致php的代码更加乱上加乱,维护起来简直一坨shit一样.随着php ...

  10. java面向对象之 封装 Encapsulation

    什么是封装:对象中的成员该隐藏的隐藏.该公开的要公开 封装:顾名思义,隐藏对象的属性和实现细节,仅对外公开接口,控制在程序中属性的读和修改的访问级别:将抽象得到的数据和行为(或功能)相结合,形成一个有 ...