哲學家就餐問題的解決(java實現)

前言:

生產者-消費者模型和哲學家就餐問題是多線程中比較經典的兩個問題.通過這兩個問題,可以很好地瞭解和實踐下java多線程的基礎知識.

哲學家就餐問題:

有五個哲學家,他們的生活方式是交替地進行思考和進餐。他們共用一張圓桌,分別坐在五張椅子上。

在圓桌上有五個碗和五支筷子,平時一個哲學家進行思考,飢餓時便試圖取用其左、右最靠近他的筷子,只有在他拿到兩支筷子時才能進餐。進餐完畢,放下筷子又繼續思考。

這裏寫圖片描述

 

對java多線程不熟悉的可以先看下生產者-消費者模型是怎麼實現的,然後再獨立實現哲學家就餐問題.

 

解決方案1:

哲學家要進餐時,要麼同時拿起兩支筷子,要麼一支筷子都不拿.

代碼實現:

package com.example.demo.thread;

public class PhilosopherQuestion {
    // chopsticks
    private boolean[] used = new boolean[] { false, false, false, false, false };
    private static String LOCK = "lock";

    public static void main(String[] args) {
        PhilosopherQuestion philosopherQuestion = new PhilosopherQuestion();
        philosopherQuestion.new Philosopher(0).start();
        philosopherQuestion.new Philosopher(1).start();
        philosopherQuestion.new Philosopher(2).start();
        philosopherQuestion.new Philosopher(3).start();
        philosopherQuestion.new Philosopher(4).start();
    }

    class Philosopher extends Thread {
        private int num;

        public Philosopher(int num) {
            this.num = num;
        }

        public void eating() {
            System.out.println("my num is " + num + " , I am eating...");
            try {
                Thread.sleep(3000);
            } catch (InterruptedException e) {
                e.printStackTrace();
            }
        }

        public void thinking() {
            System.out.println("my num is " + num + ", I am thinking...");
            try {
                Thread.sleep(3000);
            } catch (InterruptedException e) {
                e.printStackTrace();
            }
            
        }
        
        //拿筷子時只要有一個筷子已經被佔用,就要放棄拿筷子,並釋放鎖進入等待狀態
        //得到通知後,再進入就緒狀態,重新競爭鎖
        public void takeChopsticks(){
            synchronized(LOCK) {
                if (used[num] || used[(num + 1) % 5]) {
                    try {
                        LOCK.wait();
                    } catch (InterruptedException e) {
                        e.printStackTrace();
                    }
                }

                //拿到兩支筷子了    
                used[num] = true;
                used[(num + 1) % 5] = true;
            }
        }

        //放下筷子時,也要申請鎖,然後通知所有等待的線程
        public void putDownChopsticks() {
            synchronized(LOCK) {
                used[num] = false;
                used[(num + 1) % 5] = false;
                System.out.println("my num is " + num + " , I have finished...");
                LOCK.notifyAll();
            }
        }
        
        @Override
        public void run() {
            while(true) {
                thinking();
                takeChopsticks();
                eating();
                putDownChopsticks();
            }
        }
    }

}

運行結果:

my num is 0, I am thinking...
my num is 3, I am thinking...
my num is 2, I am thinking...
my num is 1, I am thinking...
my num is 4, I am thinking...
my num is 0 , I am eating...
my num is 3 , I am eating...
my num is 3 , I have finished...
my num is 3, I am thinking...
my num is 1 , I am eating...
my num is 2 , I am eating...
my num is 4 , I am eating...
my num is 0 , I have finished...
my num is 0, I am thinking...
my num is 1 , I have finished...
my num is 1, I am thinking...
my num is 4 , I have finished...
my num is 0 , I am eating...
my num is 4, I am thinking...
my num is 2 , I have finished...
my num is 2, I am thinking...
my num is 3 , I am eating...
my num is 0 , I have finished...
my num is 0, I am thinking...
my num is 1 , I am eating...
my num is 3 , I have finished...
my num is 3, I am thinking...
my num is 2 , I am eating...
my num is 4 , I am eating...
my num is 1 , I have finished...
my num is 1, I am thinking...
my num is 2 , I have finished...
my num is 2, I am thinking...
my num is 4 , I have finished...
my num is 4, I am thinking...
my num is 0 , I am eating...
my num is 3 , I am eating...
my num is 0 , I have finished...
my num is 0, I am thinking...
my num is 1 , I am eating...
my num is 4 , I am eating...
my num is 3 , I have finished...
my num is 2 , I am eating...
my num is 3, I am thinking...
my num is 1 , I have finished...
my num is 2 , I have finished...
my num is 2, I am thinking...
my num is 0 , I am eating...
my num is 1, I am thinking...
my num is 3 , I am eating...
my num is 4 , I have finished...
my num is 4, I am thinking...
my num is 3 , I have finished...
my num is 3, I am thinking...
my num is 0 , I have finished...
my num is 0, I am thinking...
my num is 4 , I am eating...
my num is 2 , I am eating...
my num is 1 , I am eating...
my num is 4 , I have finished...
my num is 4, I am thinking...
my num is 0 , I am eating...
my num is 3 , I am eating...
my num is 1 , I have finished...
my num is 1, I am thinking...
my num is 2 , I have finished...
my num is 2, I am thinking...
my num is 0 , I have finished...
my num is 0, I am thinking...
my num is 3 , I have finished...
my num is 4 , I am eating...
my num is 2 , I am eating...
my num is 3, I am thinking...
my num is 4 , I have finished...
my num is 4, I am thinking...
my num is 2 , I have finished...
my num is 0 , I am eating...
my num is 1 , I am eating...
my num is 3 , I am eating...
my num is 2, I am thinking...
my num is 0 , I have finished...
my num is 0, I am thinking...
my num is 4 , I am eating...
my num is 3 , I have finished...
my num is 1 , I have finished...
my num is 3, I am thinking...
my num is 2 , I am eating...
my num is 1, I am thinking...
my num is 4 , I have finished...
my num is 4, I am thinking...
my num is 0 , I am eating...
my num is 2 , I have finished...
my num is 2, I am thinking...
my num is 3 , I am eating...
my num is 0 , I have finished...
my num is 0, I am thinking...
my num is 3 , I have finished...
my num is 4 , I am eating...
my num is 2 , I am eating...
my num is 3, I am thinking...
my num is 1 , I am eating...
my num is 4 , I have finished...
my num is 4, I am thinking...
my num is 2 , I have finished...
my num is 0 , I am eating...
my num is 1 , I have finished...
my num is 3 , I am eating...
my num is 2, I am thinking...
my num is 1, I am thinking...

 

解決方案2:

給筷子編號,哲學家將要進餐時,要先從小號的開始拿.

代碼實現:

package com.example.demo.thread;

public class PhilosopherQuestion {
    // chopsticks
    private boolean[] used = new boolean[] { false, false, false, false, false };
    private static String LOCK = "lock";

    public static void main(String[] args) {
        PhilosopherQuestion philosopherQuestion = new PhilosopherQuestion();
        philosopherQuestion.new Philosopher1(0).start();
        philosopherQuestion.new Philosopher1(1).start();
        philosopherQuestion.new Philosopher1(2).start();
        philosopherQuestion.new Philosopher1(3).start();
        philosopherQuestion.new Philosopher1(4).start();
    }


    class Philosopher1 extends Thread {
        private int num;

        public Philosopher1(int num) {
            this.num = num;
        }

        public void eating() {
            System.out.println("my num is " + num + " , I am eating...");
            try {
                Thread.sleep(3000);
            } catch (InterruptedException e) {
                e.printStackTrace();
            }
        }

        public void thinking() {
            System.out.println("my num is " + num + ", I am thinking...");
            try {
                Thread.sleep(3000);
            } catch (InterruptedException e) {
                e.printStackTrace();
            }

        }

        public void takeChopsticks() {
            synchronized (LOCK) {
                int min = Math.min(num, (num + 1) % 5);
                int max = Math.max(num, (num + 1) % 5);
                if (!used[min]) {//先嚐試拿小號筷子,失敗則進入等待狀態,並釋放鎖
                    used[min] = true;
                    if(!used[max]) {//成功拿到小號筷子後,嘗試拿大號筷子,失敗,則進入等待狀態,並釋放鎖,但是沒有釋放小號筷子
                        used[max] = true;
                    } else {
                        try {
                            LOCK.wait();
                        } catch (InterruptedException e) {
                            e.printStackTrace();
                        }
                    }
                } else {
                    try {
                        LOCK.wait();
                    } catch (InterruptedException e) {
                        e.printStackTrace();
                    }
                }
            }
        }

        //放下筷子後,通知其他等待線程
        public void putDownChopsticks() {
            synchronized(LOCK) {
                used[num] = false;
                used[(num + 1) % 5] = false;
                System.out.println("my num is " + num + " , I have finished...");
                LOCK.notifyAll();
            }
        }
        
        @Override
        public void run() {
            while(true) {
                thinking();
                takeChopsticks();
                eating();
                putDownChopsticks();
            }
        }
    }

}

輸出爲:

my num is 1, I am thinking...
my num is 0, I am thinking...
my num is 4, I am thinking...
my num is 3, I am thinking...
my num is 2, I am thinking...
my num is 1 , I am eating...
my num is 3 , I am eating...
my num is 1 , I have finished...
my num is 1, I am thinking...
my num is 0 , I am eating...
my num is 3 , I have finished...
my num is 3, I am thinking...
my num is 2 , I am eating...
my num is 4 , I am eating...
my num is 0 , I have finished...
my num is 1 , I am eating...
my num is 0, I am thinking...
my num is 2 , I have finished...
my num is 2, I am thinking...
my num is 4 , I have finished...
my num is 4, I am thinking...
my num is 3 , I am eating...
my num is 1 , I have finished...
my num is 0 , I am eating...
my num is 1, I am thinking...
my num is 3 , I have finished...
my num is 3, I am thinking...
my num is 4 , I am eating...
my num is 2 , I am eating...
my num is 0 , I have finished...
my num is 0, I am thinking...
my num is 3 , I am eating...
my num is 4 , I have finished...
my num is 4, I am thinking...
my num is 1 , I am eating...
my num is 2 , I have finished...
my num is 2, I am thinking...
my num is 3 , I have finished...
my num is 1 , I have finished...
my num is 3, I am thinking...
my num is 2 , I am eating...
my num is 1, I am thinking...
my num is 0 , I am eating...
my num is 2 , I have finished...
my num is 2, I am thinking...
my num is 4 , I am eating...
my num is 3 , I am eating...
my num is 0 , I have finished...
my num is 0, I am thinking...
my num is 1 , I am eating...

 

發表評論
所有評論
還沒有人評論,想成為第一個評論的人麼? 請在上方評論欄輸入並且點擊發布.
相關文章