# 要求

哲学家从 04 按顺时针编号。请实现函数 void wantsToEat(philosopher, pickLeftFork, pickRightFork, eat, putLeftFork, putRightFork):

  • philosopher 哲学家的编号
  • pickLeftForkpickRightFork 表示拿起左边或右边的叉子。
  • eat 表示吃面
  • putLeftForkputRightFork 表示放下左边或右边的叉子
  • 由于哲学家不是在吃面就是在想着啥时候吃面,所以思考这个方法没有对应的回调。

给你 5 个线程,每个都代表一个哲学家,请你使用类的同一个对象来模拟这个过程。在最后一次调用结束之前,可能会为同一个哲学家多次调用该函数。

来源:https://leetcode-cn.com/problems/the-dining-philosophers

输入:n = 1
输出:[[4,2,1],[4,1,1],[0,1,1],[2,2,1],[2,1,1],[2,0,3],[2,1,2],[2,2,2],[4,0,3],[4,1,2],[0,2,1],[4,2,2],[3,2,1],[3,1,1],[0,0,3],[0,1,2],[0,2,2],[1,2,1],[1,1,1],[3,0,3],[3,1,2],[3,2,2],[1,0,3],[1,1,2],[1,2,2]]
解释:
n 表示每个哲学家需要进餐的次数。
输出数组描述了叉子的控制和进餐的调用,它的格式如下:
output[i] = [a, b, c] (3个整数)
- a 哲学家编号。
- b 指定叉子:{1 : 左边, 2 : 右边}.
- c 指定行为:{1 : 拿起, 2 : 放下, 3 : 吃面}。
如 [4,2,1] 表示 4 号哲学家拿起了右边的叉子。

# 解法

newCondition () 方法
关键字 synchronizedwait()/notify() 这两个方法一起使用可以 实现等待/通知模式Lock 锁的 newContition() 方法返回 Condition 对象, Condition 类也可以 实现等待/通知模式 。用 notify() 通知时, JVM 会随机唤醒某个等待的线程, 使用 Condition 类可以进行选择性通知。
Condition 比较常用的两个方法:

  • await() 会使当前线程等待,同时会释放锁,当其他线程调用 signal() 时,线程会重新获得锁并继续执行。
  • signal() 用于唤醒一个等待的线程。

注意:在调用 Conditionawait()/signal() 方法前,也需要线程持有相关的 Lock 锁,调用 await() 后线程会释放这个锁,在 singal() 调用后会从当前 Condition 对象的等待队列中,唤醒 一个线程,唤醒的线程尝试获得锁, 一旦获得锁成功就继续执行。
ReentrantLock
ReentrantLock 的实现是基于其内部类 FairSync (公平锁) 和 NonFairSync (非公平锁) 实现的。 其可重入性是基于 Thread.currentThread() 实现的:如果当前线程已经获得了执行序列中的锁,那执行序列之后的所有方法都可以获得这个锁。

class DiningPhilosophers {
    // 定义 lock
    public ReentrantLock lock = new ReentrantLock();
    // 定义 Condition 对象
    public Condition[] conditions = new Condition[5];
    // 叉子是否被占用
    public boolean[] forks = new boolean[5];
    public DiningPhilosophers() {
        // 创建 conditions 对象
        for(int i = 0 ; i < 5 ; i++){
            conditions[i]=lock.newCondition();
        }
    }
    // call the run() method of any runnable to execute its code
    public void wantsToEat(int philosopher,
                           Runnable pickLeftFork,
                           Runnable pickRightFork,
                           Runnable eat,
                           Runnable putLeftFork,
                           Runnable putRightFork) throws InterruptedException {
        lock.lock();
        try{
            // 定义哲学家左右叉子编号
            int leftFork=philosopher;
            int rightFork=(philosopher+1)%5;
            // 左右任意一个叉子被占用,线程等待
            if(forks[leftFork]||forks[rightFork]){
                conditions[philosopher].await();
            }
            // 占用叉子
            forks[rightFork]=true;
            forks[leftFork]=true;
            // 吃面
            pickLeftFork.run();
            pickRightFork.run();
            eat.run();
            // 放下左边的叉子
            putLeftFork.run();
            forks[leftFork]=false;
            // 唤醒左边的哲学家
            conditions[leftFork].signal();
            putRightFork.run();
            // 唤醒右边的哲学家
            forks[rightFork]=false;
            conditions[rightFork].signal();
        }finally{
            lock.unlock();
        }
    }
}
更新於 閱讀次數

請我喝[茶]~( ̄▽ ̄)~*

fygod 微信支付

微信支付

fygod 支付寶

支付寶

fygod PayPal

PayPal