zoukankan      html  css  js  c++  java
  • JAVA并发,经典死锁案例-哲学家就餐

    转自:http://blog.csdn.net/tayanxunhua/article/details/38691005

    死锁经典案例:哲学家就餐。

    这个案例会导致死锁

    通过修改《Java编程思想4》一书中的案例,来做实验,代码更易理解,结果也相对容易控制。

    附代码:

    筷子类:

     1 package com.tyxh.ch21.c6;
     2 
     3 public class Chopstick {
     4     private boolean taken = false;//判断是此筷子是否被拿起
     5     public synchronized void take() throws InterruptedException {
     6         while(taken) {
     7             //如果已被拿起,则等待
     8             wait();
     9         }
    10         //如果没有被拿起,则可以被拿起,并设置taken为true
    11         taken = true;
    12     }
    13     
    14     public synchronized void drop() {
    15         //放下筷子之后设置taken为false,并通知其他哲学家
    16         taken = false;
    17         notifyAll();
    18     }
    19 }

    哲学家类:

     1 package com.tyxh.ch21.c6;
     2 
     3 import java.util.Random;
     4 import java.util.concurrent.TimeUnit;
     5 
     6 public class Philosopher implements Runnable {
     7     private Chopstick left;//左筷子
     8     private Chopstick right;//右筷子
     9     
    10     private final int id;//哲学家编号
    11     private final int ponderFactor;//根据这个属性设置思考时间
    12     
    13     private Random rand = new Random(47);
    14     private void pause() throws InterruptedException {
    15         if(ponderFactor == 0) {
    16             return;
    17         }
    18         TimeUnit.MILLISECONDS.sleep(rand.nextInt(ponderFactor *250));
    19     }
    20     
    21     public Philosopher(Chopstick left, Chopstick right, int ident, int ponder) {
    22         this.left = left;
    23         this.right = right;
    24         this.id = ident;
    25         this.ponderFactor = ponder;
    26     }
    27     
    28     public void run() {
    29         try{
    30             while(!Thread.interrupted()) {
    31                 System.out.println(this + " " + "thinking");
    32                 pause();
    33                 right.take();
    34                 System.out.println(this + " " + "拿右筷子");
    35                 left.take();
    36                 System.out.println(this + " " + "拿左筷子");
    37                 pause();
    38                 System.out.println(this + " " + "吃");
    39                 right.drop();
    40                 System.out.println(this + " " + "放下右筷子");
    41                 left.drop();
    42                 System.out.println(this + " " + "放下左筷子");
    43             }
    44         }catch(InterruptedException e) {
    45             System.out.println(this + " 退出   ");
    46         }
    47     }
    48     
    49     public String toString() {
    50         return "Phiosopher : " + id; 
    51      }
    52 }

    测试类:

     1 package com.tyxh.ch21.c6;
     2 
     3 import java.util.concurrent.ExecutorService;
     4 import java.util.concurrent.Executors;
     5 import java.util.concurrent.TimeUnit;
     6 
     7 public class DeadlockingDiningPhilosophers {
     8     public static void main(String[] args) throws InterruptedException {
     9         int ponder = 5;
    10         if(args.length > 0) {
    11             ponder = Integer.parseInt(args[0]);
    12         }
    13         int size = 5;
    14         if(args.length > 1) {
    15             size = Integer.parseInt(args[1]);
    16         }
    17         ExecutorService exec = Executors.newCachedThreadPool();
    18         Chopstick[] stick = new Chopstick[size];
    19         
    20         for(int i = 0; i < size; i++) {
    21             stick[i] = new Chopstick();
    22         }
    23         
    24         for(int i = 0; i < size; i++) {
    25             Philosopher p = new Philosopher(stick[i], stick[(i+1)%size], i, ponder);
    26             exec.execute(p);
    27         }
    28         
    29         TimeUnit.SECONDS.sleep(3);
    30         exec.shutdownNow();
    31         
    32     }
    33 }
    34  

    可以通过命令行参数调整ponder因子设置哲学家思考时间,也可以设置筷子及哲学家的数量size。

    死锁产生的四个必要条件。

        1>互斥使用,即当资源被一个线程使用(占有)时,别的线程不能使用

        2>不可抢占,资源请求者不能强制从资源占有者手中夺取资源,资源只能由资源占有者主动释放。

        3>请求和保持,即当资源请求者在请求其他的资源的同时保持对原有资源的战友。

        4>循环等待,即存在一个等待队列:P1占有P2的资源,P2占有P3的资源,P3占有P1的资源。这样就形成了一个等待环路。

    当上述四个条件都成立的时候,便形成死锁。当然,死锁的情况下如果打破上述任何一个条件,便可让死锁消失。

    这里仅给出书中处理此死锁的解决方案(破坏第四种条件):

    方案是:

    前面哲学家拿筷子的顺序都是先拿右,再拿左,但最后一个哲学家拿筷子的顺序是先拿左,再拿右,就可以通过阻止循环等待这个死锁的条件来阻止死锁发生。

    即将代码:

    1         for(int i = 0; i < size; i++) {
    2             Philosopher p = new Philosopher(stick[i], stick[(i+1)%size], i, ponder);
    3             exec.execute(p);
    4         }

    修改为:

    1         for(int i = 0; i < size; i++) {
    2             if(i < size - 1) {
    3                 Philosopher p = new Philosopher(stick[i], stick[(i+1)%size], i, ponder);
    4                 exec.execute(p);
    5             }else {
    6                 Philosopher p = new Philosopher(stick[0], stick[i], i, ponder);
    7                 exec.execute(p);
    8             }
    9         }
  • 相关阅读:
    写了一个整人程序,较简单,有兴趣者可以看看
    Silverlight之我见——数据批示(2)
    Silverlight之我见——DataGrid数据验证
    28个HTML5特征、窍门和技术
    Silverlight之我见——数据批示(1)
    发现:Click事件也能获取鼠标单击的坐标
    用纯CSS3实现Path华丽动画
    IAP (内置购买) 服务器端代码
    Android ui utils简单实用的Android界面工具
    vue 路由部署服务器子目录问题
  • 原文地址:https://www.cnblogs.com/wubingshenyin/p/4483688.html
Copyright © 2011-2022 走看看