zoukankan      html  css  js  c++  java
  • 哲学家就餐问题(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));
    //        }
        }
    }
  • 相关阅读:
    tornado用户验证
    tornado cookie安全性
    XSS攻击
    《R语言入门》语言及环境简单介绍
    angular学习(十五)——Provider
    Tomcat 8(九)解读Tomcat组件的生命周期(Lifecycle)
    Windows之Xmanager连接linux打开Oracle视图操作
    CreateEvent和SetEvent及WaitForSingleObject的使用方法
    利用Sharepoint 创建轻量型应用之基本功能配置!
    android开发源代码分析--多个activity调用多个jni库的方法
  • 原文地址:https://www.cnblogs.com/sunupo/p/13567665.html
Copyright © 2011-2022 走看看