多线程之哲学家就餐问题(java代码含注释)

什么是哲学家就餐问题

有五个哲学家在一张桌上,他们交替思考和吃饭。每个人只能拿自己左右手边的叉子,当他们拿到两只叉子的时候才能吃饭,吃完饭就放下叉子开始思考,每个哲学家不能同时拿起两只叉子。用程序实现这个过程。
在这里插入图片描述

问题分析

根据题意,每个哲学家交替吃饭和思考,吃饭的条件是拿到两只叉子,那么如果五个哲学家都同时拿了左手边的叉子,那么永远都不可能有人能吃到饭,只能饿死。为了避免这种情况的发生,我们一次只能允许四个哲学家去拿叉子,让一个人暂时思考,等待别人吃完饭,他再去拿叉子。
在java中,我们可以利用信号量Semaphore来实现,代码如下:

代码

import java.util.concurrent.Semaphore;

public class PhilosopherTest {
    //一次只允许四个人抢叉子
    static final Semaphore count = new Semaphore(4);
    //五只叉子
    static final Semaphore[] mutex = {new Semaphore(1),
                                      new Semaphore(1),
                                      new Semaphore(1),
                                      new Semaphore(1),
                                      new Semaphore(1)};

    static class Philosopher extends Thread {

        Philosopher(String name) {
            super.setName(name);
        }

        @Override
        public void run() {
            do {
                try {
                    //只有四个人有抢叉子的资格
                    count.acquire();
                    Integer i = Integer.parseInt(super.getName());
                    //规定都先拿左手边的叉子,于是四个人左手都有叉子
                    mutex[i].acquire();
                    //大家开始抢右边的叉子
                    mutex[(i + 1) % 5].acquire();
                    //谁先抢到谁第一个开吃
                    System.out.println("哲学家" + i + "号吃饭!");
                    //吃完放下左手的叉子,对于左边人来说,就是他的右叉子,直接开吃
                    mutex[i].release();
                    //再放下右手的叉子
                    mutex[(i + 1) % 5].release();
                    //吃完了,开始思考,由于放下了右手的叉子,相当于给一个叉子没有的哲学家一个左叉子
                    count.release();
                    //模拟延迟
                    Thread.sleep(2000);
                } catch (InterruptedException e) {
                    System.out.println("异常");
                }
            } while (true);
        }
    }

    public static void main(String[] args) {
        //五个哲学家
        Philosopher p0 = new Philosopher("0");
        Philosopher p1 = new Philosopher("1");
        Philosopher p2 = new Philosopher("2");
        Philosopher p3 = new Philosopher("3");
        Philosopher p4 = new Philosopher("4");

        p0.start();
        p1.start();
        p2.start();
        p3.start();
        p4.start();

    }
}

对于代码的一些解释

1、static final Semaphore count = new Semaphore(4);
Semaphore通过acquire()count.release()方法限制了并发中线程的访问数量,这里5个线程一次只允许四个参与竞争,这样就避免了死锁。
2、static final Semaphore[] mutex = {new Semaphore(1), new Semaphore(1), new Semaphore(1), new Semaphore(1), new Semaphore(1)};
哲学家们都去争夺mutex数组中的叉子,通过信号量数组,保证一只叉子只能在一个哲学家手中。
3、mutex[(i + 1) % 5].acquire();
当i = 0时,(i + 1) % 5 = 1;当i = 1时,(i + 1) % 5 = 2;当i = 4时,(i + 1) % 5 = 1,通过这种方式,使叉子的摆放形成一个圈。

运行结果

在这里插入图片描述

  • 2
    点赞
  • 36
    收藏
    觉得还不错? 一键收藏
  • 5
    评论

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

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

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值