哲学家就餐问题Java版解决案

关于Java多线程的经典问题:哲学家就餐问题。以前在网上找过很多例子,执行的效果都不尽人意。于是阅读了一些多线程的书写了一个解决案。
因为接触多线程时间不长,写出来的东西还请大牛们多多指教。
问题描述:哲学家就餐问题可以这样表述,假设有五位哲学家围坐在一张圆形餐桌旁,做以下两件事情之一:吃饭,或者思考。吃东西的时候,他们就停止思考,思考的时候也停止吃东西。餐桌中间有一大碗意大利面,每两个哲学家之间有一只餐叉。因为用一只餐叉很难吃到意大利面,所以假设哲学家必须用两只餐叉吃东西。他们只能使用自己左右手边的那两只餐叉。哲学家就餐问题有时也用米饭和筷子而不是意大利面和餐叉来描述,因为很明显,吃米饭必须用两根筷子。
哲学家从来不交谈,这就很危险,可能产生死锁,每个哲学家都拿着左手的餐叉,永远都在等右边的餐叉(或者相反)。即使没有死锁,也有可能发生资源耗尽。例如,假设规定当哲学家等待另一只餐叉超过五分钟后就放下自己手里的那一只餐叉,并且再等五分钟后进行下一次尝试。这个策略消除了死锁(系统总会进入到下一个状态),但仍然有可能发生“活锁”。如果五位哲学家在完全相同的时刻进入餐厅,并同时拿起左边的餐叉,那么这些哲学家就会等待五分钟,同时放下手中的餐叉,再等五分钟,又同时拿起这些餐叉。
在实际的计算机问题中,缺乏餐叉可以类比为缺乏共享资源。一种常用的计算机技术是资源加锁,用来保证在某个时刻,资源只能被一个程序或一段代码访问。当一个程序想要使用的资源已经被另一个程序锁定,它就等待资源解锁。当多个程序涉及到加锁的资源时,在某些情况下就有可能发生死锁。例如,某个程序需要访问两个文件,当两个这样的程序各锁了一个文件,那它们都在等待对方解锁另一个文件,而这永远不会发生。

public class PerThread extends Thread {

    public static void main(String... arg){
        Copsticks cop = new Copsticks();

        for(int i = 0; i < 5; i++){
            PerThread per = new PerThread(i, cop);
            per.start();
        }
    }

    private int index;
    private int count = 0;

    private boolean lefCop = false;
    private boolean rightCop = false;

    private Copsticks cop = new Copsticks();

    public PerThread(int index, Copsticks cop){
        this.index = index;
        this.cop = cop;
    }

    public void run() {
        // 默认吃5次以后哲学家吃饱
        while (count < 5) {
            // 哲学家在思考
            thinking();
            // 监测筷子并获取筷子,否则等待
            takeCopsticks();
            // 获取筷子后吃饭
            eat();
            // 吃完后放下筷子
            putCopsticks();

        }

        System.out.println("哲学家" + index + ":吃饱了!");
    }

    // 哲学家思考
    private void thinking(){
        try {
            System.out.println("哲学家" + index + ":在思考。。。。");
            sleep((int)Math.abs(Math.random() * 1000));
            System.out.println("哲学家" + index + ":思考结束!");
        } catch (InterruptedException e) {
            e.printStackTrace();
        }
    }

    // 哲学家吃饭
    private void eat(){
        try {
            System.out.println("哲学家" + index + ":在吃饭。。。。");
            count++;
            sleep((int)Math.abs(Math.random() * 1000));
            System.out.println("哲学家" + index + ":吃饭结束!");
        } catch (InterruptedException e) {
            e.printStackTrace();
        }
    }

    public int getIndex() {
        return index;
    }

    public void setIndex(int index) {
        this.index = index;
    }

    public boolean isLefCop() {
        return lefCop;
    }

    public void setLefCop(boolean lefCop) {
        this.lefCop = lefCop;
    }

    public boolean isRightCop() {
        return rightCop;
    }

    public void setRightCop(boolean rightCop) {
        this.rightCop = rightCop;
    }

    // 获取筷子
    public  void takeCopsticks(){
        // synchronized关键字给共享资源Copsticks加锁
        synchronized(cop){
        PerThread per = (PerThread)Thread.currentThread();
        int index = per.getIndex();

        while(cop.used[index] && cop.used[(index + 1) % 5]){
            try {
                System.out.println("哲学家" + index + ":无法获得筷子!在等待。。。");
                // 执行共享对象的wait()发放,让线程在cop对象上等待
                cop.wait();
            } catch (InterruptedException e) {
                // TODO Auto-generated catch block
                e.printStackTrace();
            }
        }
        cop.used[index] = true;
        System.out.println("哲学家" + index + ":获得左快子!");
        per.setLefCop(true);
        cop.used[(index + 1) % 5] = true;
        System.out.println("哲学家" + index + ":获得右快子!");
        per.setRightCop(true);
        }
    }

    // 释放筷子
    public  void putCopsticks(){
        // synchronized关键字给共享资源Copsticks加锁
        synchronized(cop){
        PerThread per = (PerThread)Thread.currentThread();
        int index = per.getIndex();

        cop.used[index] = false;
        System.out.println("哲学家" + index + ":放下左快子!");
        per.setLefCop(false);
        cop.used[(index + 1) % 5] = false;
        System.out.println("哲学家" + index + ":放下右快子!");
        per.setRightCop(false);
        // 执行共享对象cop的notifyAll()方法,唤醒在这个对象cop上等待的线程
        cop.notifyAll();
        }
    }
}
/**
 *筷子类
 */
class Copsticks{    
    public boolean[] used = {false,false,false,false,false};
}
  • 0
    点赞
  • 2
    收藏
    觉得还不错? 一键收藏
  • 1
    评论
哲学家进餐问题是一个经典的并发编程问题,描述了五个哲学家围坐在一张圆桌前进餐的场景,每个哲学家需要先拿起自己左右两边的筷子才能进餐,但是每次只有一根筷子可以被拿起,如果所有哲学家都拿起了自己左边的筷子,那么他们就会陷入死锁状态。解决这个问题的方法有很多,其中比较常见的是使用资源分级的方法,即让哲学家按照一定顺序拿起筷子,避免死锁的发生。 以下是一个简单的 Java 实现: ```java public class Philosopher implements Runnable { private int id; private Object leftChopstick; private Object rightChopstick; public Philosopher(int id, Object leftChopstick, Object rightChopstick) { this.id = id; this.leftChopstick = leftChopstick; this.rightChopstick = rightChopstick; } public void run() { try { while (true) { // 拿起左边的筷子 synchronized (leftChopstick) { System.out.println("Philosopher " + id + " picks up left chopstick"); // 拿起右边的筷子 synchronized (rightChopstick) { System.out.println("Philosopher " + id + " picks up right chopstick and starts eating"); // 进餐 Thread.sleep(1000); System.out.println("Philosopher " + id + " puts down right chopstick"); } } System.out.println("Philosopher " + id + " puts down left chopstick and thinks"); // 思考 Thread.sleep(1000); } } catch (InterruptedException e) { e.printStackTrace(); } } public static void main(String[] args) { int numPhilosophers = 5; Philosopher[] philosophers = new Philosopher[numPhilosophers]; Object[] chopsticks = new Object[numPhilosophers]; for (int i = 0; i < numPhilosophers; i++) { chopsticks[i] = new Object(); } for (int i = 0; i < numPhilosophers; i++) { philosophers[i] = new Philosopher(i, chopsticks[i], chopsticks[(i + 1) % numPhilosophers]); new Thread(philosophers[i]).start(); } } } ```
评论 1
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值