解决哲学家就餐问题之奇数先拿右边筷子,再拿左边筷子,偶数则相反

1.标红的地方为算法的主要思想,理解了这问题就比较简单了;不懂的可以根据注释理解一下。

package test2;

class Philosopher extends Thread {
    
    int id;     
    private Chopsticsks chopsticsks; 

    public Philosopher(int num,Chopsticsks chopsticsks) {
        super();
        id=num;
        this.chopsticsks = chopsticsks;
    }

    public void run() {
        while (true) {
            thinking();        
            chopsticsks.take();
            eating();          
            chopsticsks.put(); 
        }
    }

    private void thinking() {
        System.out.println("哲学家 " + id + ": 开始思考!");
        try {
            sleep(5000);  
        } catch (InterruptedException e) {
            e.printStackTrace();
        }
    }

    private void eating() {
        System.out.println("哲学家" + id + " : 开始食用!");
        try {
            sleep(5000);   
        } catch (InterruptedException e) {
            e.printStackTrace();
        }
    }
}

class Chopsticsks {
    private boolean[] used = { false, false, false, false, false };    //初始化筷子为未使用

    public synchronized void take() {
        Philosopher p = (Philosopher) Thread.currentThread();
        int id = p.id;
        if(id%2==0) {

     //左边筷子不能拿直接等待,不要再去拿右边筷子
            while(used[id])
            {
                try {
                    wait();
                } catch (InterruptedException e) {
                    e.printStackTrace();
                }
            }
            System.out.println("哲学家"+id+"拿起左边筷子"+id);
            used[id]=true;    
            while(used[(id+1)%5]) {
                try {
                    wait();
                } catch (InterruptedException e) {
                    e.printStackTrace();
                }
            }
                System.out.println("哲学家"+id+"拿起右边筷子"+(id+1)%5);            
                used[(id+1)%5]=true;

        }
        else {

         //右边筷子不能拿直接等待,不要再去拿左边筷子
            while(used[(id+1)%5]) {
                try {
                    wait();
                } catch (InterruptedException e) {
                    e.printStackTrace();
                }
            }
            used[(id+1)%5]=true;
            System.out.println("哲学家"+id+"拿起右边筷子"+(id+1)%5);
            
            while(used[id]) {
                try {
                    wait();
                } catch (InterruptedException e) {
                    e.printStackTrace();
                }
            }
                System.out.println("哲学家"+id+"拿起左边筷子"+id);
                used[id]=true;
        }

    }

    @SuppressWarnings("deprecation")
    public synchronized void put() {
        Philosopher p = (Philosopher) Thread.currentThread();
        int id = p.id;
        System.out.println("哲学家" + id + "放下手中的筷子:"+id+"、" +(id + 1) % 5);
        used[id] = false;          //将筷子设为为使用
        used[(id + 1) % 5] = false;
        notifyAll();               //唤醒所有等待队列中的进程

    }
}

public class Test {
    public static void main(String[] args) {
        Chopsticsks chopsticsks = new Chopsticsks();

        new Philosopher(0,chopsticsks).start();
        new Philosopher(1,chopsticsks).start();
        new Philosopher(2,chopsticsks).start();
        new Philosopher(3,chopsticsks).start();
        new Philosopher(4,chopsticsks).start();
    }
}
运行截图

  • 2
    点赞
  • 11
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
以下是使用C语言实现的一个解决方案,其中使用了信号量来实现资源的配和释放。在该解决方案中,奇数哲学家左边筷子再拿右边筷子偶数哲学家则反之: ```c #include <stdio.h> #include <stdlib.h> #include <pthread.h> #include <semaphore.h> #define NUM_PHILOSOPHERS 5 pthread_t philosophers[NUM_PHILOSOPHERS]; sem_t forks[NUM_PHILOSOPHERS]; sem_t max_philosophers; int ids[NUM_PHILOSOPHERS]; void *philosopher(void *arg) { int id = *(int *)arg; int left = id; int right = (id + 1) % NUM_PHILOSOPHERS; while (1) { sem_wait(&max_philosophers); // 等待最多只有四个哲学家同时进餐 if (id % 2 == 0) { sem_wait(&forks[right]); // 拿右手的筷子 sem_wait(&forks[left]); // 再拿左手的筷子 } else { sem_wait(&forks[left]); // 拿左手的筷子 sem_wait(&forks[right]); // 再拿右手的筷子 } // 进餐 printf("Philosopher %d is eating.\n", id); sleep(3); sem_post(&forks[left]); // 放下左手的筷子 sem_post(&forks[right]); // 放下右手的筷子 sem_post(&max_philosophers); // 释放一个位置 printf("Philosopher %d is thinking.\n", id); sleep(3); } } int main() { int i; for (i = 0; i < NUM_PHILOSOPHERS; i++) { sem_init(&forks[i], 0, 1); ids[i] = i; } sem_init(&max_philosophers, 0, 4); // 初始值为4,表示最多只允许四个哲学家同时进餐 for (i = 0; i < NUM_PHILOSOPHERS; i++) { pthread_create(&philosophers[i], NULL, philosopher, &ids[i]); } for (i = 0; i < NUM_PHILOSOPHERS; i++) { pthread_join(philosophers[i], NULL); } for (i = 0; i < NUM_PHILOSOPHERS; i++) { sem_destroy(&forks[i]); } sem_destroy(&max_philosophers); return 0; } ``` 在上面的代码中,每个哲学家都是一个线程,使用信号量来控制进餐时的资源配和释放。在进餐前,奇数哲学家尝试获取左手的筷子,再尝试获取右手的筷子,而偶数哲学家则反之。这样可以避免出现所有哲学家同时拿起左手或右手的筷子而导致死锁的情况。进餐结束后,需要释放左手和右手的筷子,并将`max_philosophers`信号量加1,表示有一个哲学家离开了餐桌。 这个解决方案可以避免死锁和资源竞争问题,并满足奇数哲学家左边筷子再拿右边筷子偶数哲学家反之的要求。

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

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

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值