• 通过锁对象解决哲学家就餐问题


    问题描述


    • 哲学家进餐问题:5个哲学家共用一张圆桌,分别坐在周围的5张椅子上,在圆桌上有5个碗和5只筷子(注意是5只筷子,不是5双),碗和筷子交替排列。他们的生活方式是交替地进行思考(thinking)和进餐(eating)。平时,一个哲学家进行思考,饥饿时便试图取用其左右最靠近他的两只筷子,规定他必须先取左边的筷子,再取右边的筷子。只有在他拿到两只筷子时才能进餐。进餐完毕,放下筷子继续进行思考。假如5位哲学家同时饥饿,各自拿起左边的筷子时,再去拿各自右边的筷子,因为无筷子可拿而陷入无期限等待(死锁)。一种解决的办法是:至多只允许有4位哲学家同时去拿左边的筷子,最终能保证至少有一位哲学家能够拿到两只筷子,从而进餐。进餐完毕释放他用过的两只筷子,从而使更多的哲学家能够进餐。使用Java的多线程同步技术,实现上述解决方案。

    主方法


    package cn.learn.thread.ThreadState.practice;
    //测试
    public class Test {
        public static void main(String[] args) {
    
            //五根筷子对象
            Chopsticks[] chopsticks = new Chopsticks[5];
            for (int i = 0; i <5 ; i++) {
                chopsticks[i] = new Chopsticks("---筷子"+i);
            }
    
            //创建五位哲学家进程,并传递其左右两边筷子
            for (int i = 0; i < 5; i++) {
                Philosopher philosopher = new Philosopher("哲学家"+(i + 1)+": ",chopsticks[(i+1)%5],chopsticks[i]);
                philosopher.start();
            }
    
        }
    }
    
    
    

    筷子类


    package cn.learn.thread.ThreadState.practice;
    
    /*
    
      共享资源:筷子
    
     */
    public class Chopsticks {
    
        private String chopsticksName;
    
        public Chopsticks(String chopsticksName) {
            this.chopsticksName = chopsticksName;
        }
    
        public String getChopsticksName() {
            return chopsticksName;
        }
    
        public void setChopsticksName(String chopsticksName) {
            this.chopsticksName = chopsticksName;
        }
    }
    
    

    哲学家进程


    package cn.learn.thread.ThreadState.practice;
    
    import java.util.Random;
    
    public class Philosopher extends Thread {
    
    
        //左筷子
        private Chopsticks leftChopsticks;
        //右筷子
        private Chopsticks rightChopsticks;
        //静态引用类型保证同步时为同一把锁
        private static Object obj = new Object();
        private static int flag = 5;
    
    
        public Philosopher(String name, Chopsticks leftChopsticks, Chopsticks rightChopsticks) {
            //调用父方法给进程取名字
            super(name);
            this.leftChopsticks = leftChopsticks;
            this.rightChopsticks = rightChopsticks;
        }
    
    
        @Override
        public void run() {
            while (true) {
                thinking();
                takeChopsticks();
            }
        }
    
        //思考
        private void thinking() {
            //获取当前进程名称
            String threadName = Thread.currentThread().getName();
            Random random = new Random();
            //睡眠,不释放锁
            try {
                sleep(random.nextInt(10000)+1000);
            } catch (InterruptedException e) {
                e.printStackTrace();
            }
            System.out.println(threadName + "思考中。。。");
        }
    
        //拿筷子
        public void takeChopsticks() {
            //让前四个哲学家先拿筷子
            synchronized (obj) {
                //如果只剩一个哲学家让他等待
                if (flag == 1) {
                    try {
                        obj.wait();
                    } catch (InterruptedException e) {
                        e.printStackTrace();
                    }
                }
                //思考人数--
                flag--;
            }
            //进程进来先给左筷子请求进入并上锁,再请求右筷子
            synchronized (leftChopsticks) {
                //获取当前进程名称
                String threadName = Thread.currentThread().getName();
                //获取当前进程筷子
                String chopsticksName = leftChopsticks.getChopsticksName();
                //哲学家拿左筷子
                System.out.println(threadName + "拿起一根左筷子" + chopsticksName);
    
    
                synchronized (rightChopsticks) {
                    //获取当前进程筷子
                    chopsticksName = rightChopsticks.getChopsticksName();
                    System.out.println(threadName + "拿起一根右筷子" + chopsticksName + "开始吃饭!");
                }
                //方法结束释放锁对象筷子
    
            }
            //唤醒没有拿到筷子的哲学家
            synchronized (obj) {
                obj.notify();
                flag++;
            }
        }
    }
    
    

    代码总结


    • 五个哲学家在争抢筷子时,由系统调度,从而可能发生死锁,通过设置flag来解决使得有一名哲学家不能进餐,当有一个人进餐完成后,flag++,思考的人员增加;通过随机设置思考睡眠时间,可以达到五个哲学家可以随机有两个人同时吃饭。
  • 相关阅读:
    JDBCUtils
    C3P0配置
    反射基本常识(二)
    反射基本常识(一)
    String to Integer (atoi)
    ZigZag Conversion
    Longest Palindromic Substring
    Palindrome Number
    Reverse Integer
    Longest Substring Without Repeating Characters
  • 原文地址:https://www.cnblogs.com/huxiaobai/p/11805447.html
Copyright © 2020-2023  润新知