返回博主主页

哲学家就餐问题(java)——同时只能有一个人去拿筷子,而且必须同时拿起两根筷子

1.处理方式。同时只能有一个人去拿筷子,而且必须同时拿起两根筷子。所以用了一个mutex信号量。

解释:

假设当前用户A获得了mutex信号量之后,A先去拿left筷子,A再去right筷子。假设A此刻left拿不起来,说明有人(假设是B)在拿起了这根left筷子,同时B肯定也拿起了B需要的另一根筷子(因为如果B没有拿起B需要的另一个筷子,B就不会释放mutex,从而A就不能获得mutex,更别说A能拿起这根left筷子了),
所以B是能够吃上饭的。吃完饭便能放下这个left筷子,让A拿这根left子。同理A也能拿到right筷子。
import java.util.Arrays;
import java.util.Date;
import java.util.concurrent.Semaphore;

enum PhiState{
    THINKING,EATING,HUNGRY
}
/**
 * 死锁问题被认为是线程/进程间切换消耗系统性能的一种极端情况。
 * 在死锁时,线程/进程间相互等待资源,而又不释放自身的资源,导致无穷无尽的等待,其结果是任务永远无法执行完成。
 * 哲学家问题便是线程资源竞争导致的死锁现象,在程序运行一段时间后,程序所处的状态是n位哲学家(n个线程)都各自获取了一只筷子的状态,
 * 此时所有哲学家都想获取第二只筷子去吃饭,但是共享资源n只筷子已经都被n位哲学家握在手里了,
 * 彼此想要的筷子都在其他哲学家手中,又没有机制能让任何哲学家放弃握在手中的筷子,从而照成了所有哲学家(所有线程)都在等待其他人手中资源的死锁问题。
 * @author win7
 *
 */
//只要不存在每个人都拿起一根筷子,再想拿另一个筷子的时候都没有,就不会产生死锁。
public class PhiEat {
    Semaphore[] s;  // 每个资源对应一个信号量(筷子)
    Semaphore mutex;  // 互斥信号量,保证每次拿筷子的只有一个人
    volatile PhiState[] state;  // 记录哲学家当前的状态()
    int n;
    public PhiEat(int n) {
        // TODO Auto-generated constructor stub
        s = new Semaphore[n];
        for (int i = 0; i < s.length; i++) {
            s[i] = new Semaphore(1);
        }
        mutex = new Semaphore(1);
        state = new PhiState[n];
        for (int i = 0; i < state.length; i++) {
            state[i]=PhiState.THINKING;
        }
        this.n = n;
    }
    
//    拿起两根筷子
    public void take_two(int i){
        int left = (i+n-1)%n;
        int right = (i+1)%n;
        try {
            mutex.acquire(); //因为有一个mutex信号量,保证了每次拿筷子的只有一个人。其他人要么此刻拿起来了两根筷子,要么一根筷子也没拿。
            s[left].acquire();
            s[right].acquire();
            mutex.release();
        } catch (Exception e) {
            e.printStackTrace();
        }
    }

//    放下两根筷子
    public void put_two(int i){
        int left = (i+n-1)%n;
        int right = (i+1)%n;
        s[left].release();
        s[right].release();
    }
    
    public void eat(int i){
        try {
            state[i] = PhiState.EATING;
            System.out.println("哲学家"+i+"开始吃东西eating");
//            Thread.sleep(1000);
            state[i] = PhiState.THINKING;
            System.out.println("哲学家"+i+"eating结束, 开始thinking");
        } catch (Exception e) {
            e.printStackTrace();
        }
    }
    public void think(int i){
        try {
            System.out.println("哲学家"+i+"正在思考thinking");
//            Thread.sleep(1000);
            state[i] = PhiState.HUNGRY;
            System.out.println("哲学家"+i+"thinking结束,变得hungry");
        } catch (Exception e) {
            e.printStackTrace();
        }
    }
    
    public void philosopher(int i){
        while(true){
            think(i);
            take_two(i);
            eat(i);
            put_two(i);
        }
    }
    public static void main(String[] args) throws InterruptedException {
        final int N=10;
        PhiEat pe = new PhiEat(N);
        for (int i = 0; i < N; i++) {
            final int num = i;
            new Thread(()->pe.philosopher(num)).start();
        }
//        本来是想在主线程用循环去查询当前线程的状态,但是在子线程中①号语句执行完毕,②号语句执行之前,可能切换到了主线程输出了当前线程的状态,导致②号语句没来得及打印
//        state[i] = PhiState.HUNGRY; ////        System.out.println("哲学家"+i+"thinking结束,变得hungry");  ////        while(true){
//            Thread.sleep(100);
//            System.out.println(Arrays.toString(pe.state));
//        }
    }
}

 

posted @ 2020-08-26 20:41  懒惰的星期六  阅读(453)  评论(0编辑  收藏  举报

Welcome to here

主页