[CareerCup] 16.3 Dining Philosophers 哲學家聚餐問題


 

16.3 In the famous dining philosophers problem, a bunch of philosophers are sitting around a circular table with one chopstick between each of them. A philosopher needs both chopsticks to eat, and always picks up the left chopstick before the right one. A deadlock could potentially occur if all the philosophers reached for the left chopstick at the same time. Using threads and locks, implement a simulation of the dining philosophers problem that prevents deadlocks.

 

經典的哲學家聚餐問題,說是有一堆哲學家圍着一個圓桌子坐着吃飯,每兩個人之間都有一根筷子,每個人吃飯需要都需要左右兩邊的筷子,而且是先拿起左邊的筷子,再拿右邊的筷子,那么如果當所有的哲學家都拿着左邊的筷子,那么就會產生死鎖的情況。如果我們先不考慮死鎖的問題,先來實現這個問題。我們可以把每個哲學家都當做一個線程,然后筷子被哲學家拿起后可以調用鎖,當被放下后調用解鎖,參見代碼如下:

 

import java.util.concurrent.locks.Lock;
import java.util.concurrent.locks.ReentrantLock;

public class Chopstick {
    private Lock lock;
    public Chopstick() {
        lock = new ReentrantLock();
    }
    public void pickUp() {
        lock.lock();
    }
    public void putDown() {
        lock.unlock();
    }
}

public class Philosopher extends Thread {
    private final int maxPause = 100;
    private int bites = 10;
    private Chopstick left;
    private Chopstick right;
    private int index;
    
    public Philosopher(int i, Chopstick left, Chopstick right) {
        this.left = left;
        this.right = right;
    }
    
    public void eat() {
        System.out.println("Philosopher" + index + ": start eating");
        pickUp();
        chew();
        putDown();
        System.out.println("Philosopher " + index + ": done eating");
    }
    
    public void pickUp() {
        pause();
        left.pickUp();
        pause();
        right.pickUp();
    }
    
    public void chew() {
        System.out.println("Philosopher " + index + ": eating");
        pause();
    }
    
    public void pause() {
        try {
            int pause = (int)(Math.random() * maxPause);
            Thread.sleep(pause);
        } catch (InterruptedException e) {
            e.printStackTrace();
        }
    }
    
    public void putDown() {
        left.putDown();
        right.putDown();
    }
    
    public void run() {
        for (int i = 0; i < bites; ++i) {
            eat();
        }
    }
}

public class j {
    public static int size = 3;
    
    public static int leftOf(int i) {
        return i;
    }
    
    public static int rightOf(int i) {
        return (i + 1) % size;
    }
    
    public static void main(String[] args) {
        Chopstick[] chopsticks = new Chopstick[size + 1];
        for (int i = 0; i < size + 1; ++i) {
            chopsticks[i] = new Chopstick();
        }
        
        Philosopher[] philosophers = new Philosopher[size];
        for (int i = 0; i < size; ++i) {
            Chopstick left = chopsticks[leftOf(i)];
            Chopstick right = chopsticks[rightOf(i)];
            philosophers[i] = new Philosopher(i, left, right);
        }
        
        for (int i = 0; i < size; ++i) {
            philosophers[i].start();
        }
    }
}

 

上面的代碼在執行中基本都會陷入死循環,因為發生了死鎖的情況,所以我們應該想機制來避免死鎖的發生,那么怎么做呢,我們首先想想死鎖是怎么形成的,是因為每個人都拿着左邊的筷子不放,又無法拿到右邊的筷子,所以就一直僵持着,那么我們換個思路想想,如果每個人在拿了左筷子,發現沒法取得右筷子后,就把左筷子放下,這樣就可以避免死鎖的形成。那么我們在Chopstik類中的pickUp函數中就應該使用tryLock()來代替lock,這樣只有在有左筷子的時候才能鎖上左筷子,而且在Philosopher類中的pickUp函數中,先判斷能不能拿左筷子,不能拿直接返回false,能拿的話再來看能不能拿右筷子,不能拿的話,先把左筷子放下,再返回false,能拿的話返回true。這樣在eat函數中先看pickUp是否能返回true,能返回的話再繼續運行之后的東西,參見代碼如下:

 

import java.util.concurrent.locks.Lock;
import java.util.concurrent.locks.ReentrantLock;

public class Chopstick {
    private Lock lock;
    public Chopstick() {
        lock = new ReentrantLock();
    }
    public boolean pickUp() {
        return lock.tryLock();
    }
    public void putDown() {
        lock.unlock();
    }
}

public class Philosopher extends Thread {
    private final int maxPause = 100;
    private int bites = 10;
    private Chopstick left;
    private Chopstick right;
    private int index;
    
    public Philosopher(int i, Chopstick left, Chopstick right) {
        index = i;
        this.left = left;
        this.right = right;
    }
    
    public void eat() {
        System.out.println("Philosopher" + index + ": start eating");
        if (pickUp()) {
            chew();
            putDown();
            System.out.println("Philosopher " + index + ": done eating");
        } else {
            System.out.println("Philosopher " + index + ": gave up on eating");
        }
    }
    
    public boolean pickUp() {
        pause();
        if (!left.pickUp()) {
            return false;
        }
        pause();
        if (!right.pickUp()) {
            left.putDown();
            return false;
        }
        pause();
        return true;
    }
    
    public void chew() {
        System.out.println("Philosopher " + index + ": eating");
        pause();
    }
    
    public void pause() {
        try {
            int pause = (int)(Math.random() * maxPause);
            Thread.sleep(pause);
        } catch (InterruptedException e) {
            e.printStackTrace();
        }
    }
    
    public void putDown() {
        left.putDown();
        right.putDown();
    }
    
    public void run() {
        for (int i = 0; i < bites; ++i) {
            eat();
        }
    }
}

public class j {
    public static int size = 3;
    
    public static int leftOf(int i) {
        return i;
    }
    
    public static int rightOf(int i) {
        return (i + 1) % size;
    }
    
    public static void main(String[] args) {
        Chopstick[] chopsticks = new Chopstick[size + 1];
        for (int i = 0; i < size + 1; ++i) {
            chopsticks[i] = new Chopstick();
        }
        
        Philosopher[] philosophers = new Philosopher[size];
        for (int i = 0; i < size; ++i) {
            Chopstick left = chopsticks[leftOf(i)];
            Chopstick right = chopsticks[rightOf(i)];
            philosophers[i] = new Philosopher(i, left, right);
        }
        
        for (int i = 0; i < size; ++i) {
            philosophers[i].start();
        }
    }
}

 

CareerCup All in One 題目匯總

 


免責聲明!

本站轉載的文章為個人學習借鑒使用,本站對版權不負任何法律責任。如果侵犯了您的隱私權益,請聯系本站郵箱yoyou2525@163.com刪除。



 
粵ICP備18138465號   © 2018-2025 CODEPRJ.COM