1. 程式人生 > >哲學家就餐問題 Java語言實現

哲學家就餐問題 Java語言實現

1. 哲學家就餐問題描述

本文部分內容來源於,欲瞭解詳細內容,自行點選檢視。
這裡寫圖片描述

為了不失一般性,我們假設有n個哲學家,圍著餐桌思考宇宙、人生問題,每個哲學家面前有一個叉子與之對應,即:共有n個叉子;當哲學家思考一段時間後,他會拿起身邊的2個叉子才能進食。進食完畢後,該哲學家放下叉子,繼續思考人生、宇宙,如此往復,周而復始。

2. 解決方案

在解決該類問題時,屬於競爭資源情形,假設所有哲學家均同時取得其同一方向(如左手邊)的叉子時,可能出現了死鎖問題。

死鎖:死鎖是這樣一種情形,當每個程序都已經佔據某個資源,同時等待另一個資源時,因為條件無法滿足而使系統停滯的現象。
活鎖:一個執行緒響應另一個執行緒的請求,同時另一個執行緒響應其他執行緒的請求。執行緒之間為響應互相的請求而實際未做任何實際工作,從而使得系統陷入飢餓狀態。例項:2人A和B在走廊相向而行,A向左邊移動讓B通過,B向右邊移動讓A通過,然後反轉,周而復始,實際上2人都被對方阻塞。

package com.fqyuan.philosophy;

public class Philosopher implements Runnable {
    // The forks on either side of this Philosopher
    private Object leftFork;
    private Object rightFork;

    public Philosopher(Object leftFork, Object rightFork) {
        this.leftFork = leftFork;
        this.rightFork = rightFork;
    }

    private
void doAction(String action) throws InterruptedException { System.out.println(Thread.currentThread().getName() + " " + action); Thread.sleep((int) (Math.random() * 100)); } @Override public void run() { try { while (true) { // Thinking doAction(System.nanoTime() + ": Thinking"
); synchronized (leftFork) { doAction(System.nanoTime() + ": Picked up left fork."); synchronized (rightFork) { // Eating doAction(System.nanoTime() + ": Picked up right fork - eating."); // Finish eating doAction(System.nanoTime() + ": Put down right fork."); } // Back to thinking. doAction(System.nanoTime() + ": Put down left fork. Back to thinking."); } } } catch (InterruptedException e) { Thread.currentThread().interrupt(); return; } } } //DiningPhilosopers.java package com.fqyuan.philosophy; public class DinningPhilosophers { public static void main(String[] args) { Philosopher[] philosophers = new Philosopher[5]; Object[] forks = new Object[philosophers.length]; for (int i = 0; i < forks.length; i++) forks[i] = new Object(); for (int i = 0; i < philosophers.length; i++) { Object leftFork = forks[i]; Object rightFork = forks[(i + 1) % forks.length]; philosophers[i] = new Philosopher(leftFork, rightFork); Thread t = new Thread(philosophers[i], "Philosopher " + (i + 1)); t.start(); } } }
Philosopher 1 73695516987788: Thinking
Philosopher 3 73695517303786: Thinking
Philosopher 2 73695517036856: Thinking
Philosopher 4 73695517958611: Thinking
Philosopher 5 73695518115243: Thinking
Philosopher 4 73695531258038: Picked up left fork.
Philosopher 3 73695556574779: Picked up left fork.
Philosopher 1 73695556574779: Picked up left fork.
Philosopher 5 73695591774360: Picked up left fork.
Philosopher 2 73695617427502: Picked up left fork.

Q:如何避免死鎖發生呢?
A:打破迴圈等待條件,做如下修改。

package com.fqyuan.philosophy;

public class DinningPhilosophers {

    public static void main(String[] args) {
        Philosopher[] philosophers = new Philosopher[5];
        Object[] forks = new Object[philosophers.length];

        for (int i = 0; i < forks.length; i++)
            forks[i] = new Object();

        for (int i = 0; i < philosophers.length; i++) {
            Object leftFork = forks[i];
            Object rightFork = forks[(i + 1) % forks.length];
            // Let the last philosopher get the fork in the reversed order to
            // break the circular waiting condition.
            if (i == philosophers.length - 1) // Add the line here.
                philosophers[i] = new Philosopher(rightFork, leftFork);
            else
                philosophers[i] = new Philosopher(leftFork, rightFork);
            Thread t = new Thread(philosophers[i], "Philosopher " + (i + 1));
            t.start();

        }
    }

}