死锁例证:哲学家就餐

由Edsger Dijkstra提出的哲学家就餐问题是一个经典的死锁例证。该问题的基本描述中是指定五个哲学家(本例中可以自由指定数目)。这些哲学家将花部分时间思考,花部分时间就餐。当他们思考时,不需要任何共享资源;但当他们就餐时,将使用有限的餐具。在问题的原始描述中,餐具是叉子,但在本例中,将使用筷子。很明显,哲学家就餐需要两根筷子。
问题中引入的难点是:作为哲学家,他们很穷,所以他们只能买五根筷子(更一般的讲,筷子和哲学家的数量相同)。他们围坐在桌子周围,每两人之间放一根筷子。当一个哲学家要就餐的时候,这个哲学家必须同时得到左边和右边的筷子。如果一个哲学家左边或右边的筷子已经有人在使用了,那么这个哲学家必须等待,直至可得到必需的筷子。
ponder参数用以设置思考和吃饭时长,如果有许多Philosopher,或者他们花费很多时间去思考,那么经管存在死锁的可能,但你可能永远看不到死锁。将ponder设置为0将倾向于使死锁尽快发生。
本人使用的判断所有任务是否全部挂起以此判断是否发生死锁,事实上毫无意义。你可以将ponder参数设为0,并使main()线程休眠一段时间,这样可能很快你就会看到死锁的发生。

//哲学家就餐
import java.util.concurrent.*;
import java.util.*;
import java.io.*;
class Chopstick
{
   private  boolean taken=false;
    public synchronized void take(Philosopher th,String s) throws InterruptedException
    {
        if (taken == true) System.out.println(th + s + "已被人已被人占据");
        else System.out.println(th + s + "成功获取");
        while (taken)//如果已被他人占据,本人等待
        {
            th.wait=true;
            wait();
        }
        taken=true;//被本人占据
    }
    public synchronized void drop(Philosopher[] p)
    {
        taken=false;
        for(int i=0;i<p.length;i++)
            p[i].wait=false;
        notifyAll();//唤醒所有任务,至于某些任务是否能得到筷子,看速度
    }
}
class Philosopher implements Runnable
{
   private Chopstick left;
   private Chopstick right;

   private Philosopher[] p;

   boolean wait=false;//判断当前任务是否被挂起
    private final int id;
    private final int ponderFactor;//暂停时间相关
    private Random rand=new Random(47);
    public Philosopher(Chopstick left,Chopstick right,int ident,int ponder,Philosopher[] p)
    {
        this.left=left;
        this.right=right;
        this.id=ident;
        this.ponderFactor=ponder;
        this.p=p;
    }
    private void pause() throws InterruptedException
    {
        if(ponderFactor==0)
            return;
        TimeUnit.MILLISECONDS.sleep(ponderFactor*250);
    }
    public void run()
    {
        try
        {
            while(!Thread.interrupted() )
            {
                System.out.println(this+" "+"思考一段时间 ");
                pause();
                System.out.print(this+" "+"尝试获取右筷子");
                right.take(this,"右筷子");
                System.out.print(this+" "+"尝试获取左筷子");
                left.take(this,"左筷子");
                System.out.println(this+" 吃饭一段时间 ");
                pause();
                right.drop(p);
                left.drop(p);
            }
        }
        catch(InterruptedException e)
        {
            System.out.println(this+"异常终止");
        }
    }
    public String toString()
    {
        return "  哲学家:"+id+" ";
    }
}

public class DeadLocking
{
    public static void main(String []args) throws Exception
    {
        int ponder = 5;//随机数种子,用于给定思考和吃饭时间,0
        int size = 5;//筷子数目,同样也是哲学家数目 
        Scanner scanf = new Scanner(System.in);
        ponder = scanf.nextInt();
        size = scanf.nextInt();
        ExecutorService exec = Executors.newCachedThreadPool();

        Chopstick[] chopsticks = new Chopstick[size];
        for (int i = 0; i < chopsticks.length; i++)
            chopsticks[i] = new Chopstick();

        Philosopher[] philosophers = new Philosopher[size];
        for (int i = 0; i < size; i++)
            philosophers[i] = new Philosopher(chopsticks[i], chopsticks[(i + 1) % size], i, ponder,philosophers);

        for (int i = 0; i < size; i++)
        {
            exec.execute(philosophers[i]);
        }
     //   TimeUnit.SECONDS.sleep(5);
       int k = 0;
        while (k!= size)
        {
            k = 0;
            for (int i = 0; i < size; i++)
            {
                if (philosophers[i].wait == true)
                {
                    k++;
                }
            }
        }
        if(k==size)
        {
            System.out.println("死锁出现!!!!!!!!!");
            exec.shutdownNow();
        }
        //exec.shutdownNow();
    }
}

在这里插入图片描述

  • 4
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值