题目链接:点击打开链接
题目大意:略。
解题思路
位运算难点理解(00000,0未占用,1占用)
- (expect & mask) > 0:如果有占用到其中一把刀,则一定是大于 0,否则没被占用
 - fork.compareAndSet(expect, expect ^ mask):异或运算业务理解,只要这把刀上被占用,则标记为 1,否则 0
 
Ps:解决方案(7) 一直超时,难道是因为 sync 太占用时间了?单次平台上运算的时候 n = 11 都没超时呢!
相关企业
- 谷歌(Google)
 
AC 代码
// 解决方案(1)
class DiningPhilosophers {
    //1个Fork视为1个ReentrantLock,5个叉子即5个ReentrantLock,将其都放入数组中
    private final ReentrantLock[] lockList = {new ReentrantLock(),
            new ReentrantLock(),
            new ReentrantLock(),
            new ReentrantLock(),
            new ReentrantLock()};
    //限制 最多只有4个哲学家去持有叉子
    private Semaphore eatLimit = new Semaphore(4);
    public DiningPhilosophers() {
    }
    // 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 {
        int leftFork = (philosopher + 1) % 5;    //左边的叉子 的编号
        int rightFork = philosopher;    //右边的叉子 的编号
        eatLimit.acquire();    //限制的人数 -1
        lockList[leftFork].lock();    //拿起左边的叉子
        lockList[rightFork].lock();    //拿起右边的叉子
        pickLeftFork.run();    //拿起左边的叉子 的具体执行
        pickRightFork.run();    //拿起右边的叉子 的具体执行
        eat.run();    //吃意大利面 的具体执行
        putLeftFork.run();    //放下左边的叉子 的具体执行
        putRightFork.run();    //放下右边的叉子 的具体执行
        lockList[leftFork].unlock();    //放下左边的叉子
        lockList[rightFork].unlock();    //放下右边的叉子
        eatLimit.release();//限制的人数 +1
    }
}
// 解决方案(2)
class DiningPhilosophers {
    //1个Fork视为1个ReentrantLock,5个叉子即5个ReentrantLock,将其都放入数组中
    private final ReentrantLock[] lockList = {new ReentrantLock(),
            new ReentrantLock(),
            new ReentrantLock(),
            new ReentrantLock(),
            new ReentrantLock()};
    //让 1个哲学家可以 “同时”拿起2个叉子(搞个临界区)
    private ReentrantLock pickBothForks = new ReentrantLock();
    public DiningPhilosophers() {
    }
    // 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 {
        int leftFork = (philosopher + 1) % 5;    //左边的叉子 的编号
        int rightFork = philosopher;    //右边的叉子 的编号
        pickBothForks.lock();    //进入临界区
        lockList[leftFork].lock();    //拿起左边的叉子
        lockList[rightFork].lock();    //拿起右边的叉子
        pickLeftFork.run();    //拿起左边的叉子 的具体执行
        pickRightFork.run();    //拿起右边的叉子 的具体执行
        pickBothForks.unlock();    //退出临界区
        eat.run();    //吃意大利面 的具体执行
        putLeftFork.run();    //放下左边的叉子 的具体执行
        putRightFork.run();    //放下右边的叉子 的具体执行
        lockList[leftFork].unlock();    //放下左边的叉子
        lockList[rightFork].unlock();    //放下右边的叉子
    }
}
// 解决方案(3)
class DiningPhilosophers {
    //1个Fork视为1个ReentrantLock,5个叉子即5个ReentrantLock,将其都放入数组中
    private final ReentrantLock[] lockList = {new ReentrantLock(),
            new ReentrantLock(),
            new ReentrantLock(),
            new ReentrantLock(),
            new ReentrantLock()};
    public DiningPhilosophers() {
    }
    // 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 {
        int leftFork = (philosopher + 1) % 5;    //左边的叉子 的编号
        int rightFork = philosopher;    //右边的叉子 的编号
        //编号为偶数的哲学家,优先拿起左边的叉子,再拿起右边的叉子
        if (philosopher % 2 == 0) {
            lockList[leftFork].lock();    //拿起左边的叉子
            lockList[rightFork].lock();    //拿起右边的叉子
        }
        //编号为奇数的哲学家,优先拿起右边的叉子,再拿起左边的叉子
        else {
            lockList[rightFork].lock();    //拿起右边的叉子
            lockList[leftFork].lock();    //拿起左边的叉子
        }
        pickLeftFork.run();    //拿起左边的叉子 的具体执行
        pickRightFork.run();    //拿起右边的叉子 的具体执行
        eat.run();    //吃意大利面 的具体执行
        putLeftFork.run();    //放下左边的叉子 的具体执行
        putRightFork.run();    //放下右边的叉子 的具体执行
        lockList[leftFork].unlock();    //放下左边的叉子
        lockList[rightFork].unlock();    //放下右边的叉子
    }
}
// 解决方案(4)
class DiningPhilosophers {
    //初始化为0, 二进制表示则为00000, 说明当前所有叉子都未被使用
    private AtomicInteger fork = new AtomicInteger(0);
    //每个叉子的int值(即二进制的00001, 00010, 00100, 01000, 10000)
    private final int[] forkMask = new int[]{1, 2, 4, 8, 16};
    //限制 最多只有4个哲学家去持有叉子
    private Semaphore eatLimit = new Semaphore(4);
    public DiningPhilosophers() {
    }
    // 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 {
        int leftMask = forkMask[(philosopher + 1) % 5], rightMask = forkMask[philosopher];
        eatLimit.acquire();    //限制的人数 -1
        while (!pickFork(leftMask)) Thread.sleep(1);    //拿起左边的叉子
        while (!pickFork(rightMask)) Thread.sleep(1);   //拿起右边的叉子
        pickLeftFork.run();    //拿起左边的叉子 的具体执行
        pickRightFork.run();    //拿起右边的叉子 的具体执行
        eat.run();    //吃意大利面 的具体执行
        putLeftFork.run();    //放下左边的叉子 的具体执行
        putRightFork.run();    //放下右边的叉子 的具体执行
        while (!putFork(leftMask)) Thread.sleep(1);     //放下左边的叉子
        while (!putFork(rightMask)) Thread.sleep(1);    //放下右边的叉子
        eatLimit.release(); //限制的人数 +1
    }
    private boolean pickFork(int mask) {
        int expect = fork.get();
        return (expect & mask) > 0 ? false : fork.compareAndSet(expect, expect ^ mask);
    }
    private boolean putFork(int mask) {
        int expect = fork.get();
        return fork.compareAndSet(expect, expect ^ mask);
    }
}
// 解决方案(5)
class DiningPhilosophers {
    //初始化为0, 二进制表示则为00000, 说明当前所有叉子都未被使用
    private AtomicInteger fork = new AtomicInteger(0), both = new AtomicInteger(0);
    //每个叉子的int值(即二进制的00001, 00010, 00100, 01000, 10000)
    private final int[] forkMask = new int[]{1, 2, 4, 8, 16};
    public DiningPhilosophers() {
    }
    // 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 {
        int leftMask = forkMask[(philosopher + 1) % 5], rightMask = forkMask[philosopher];
        while (!both.compareAndSet(0, 1)) Thread.sleep(1);     //进入临界区
        while (!pickFork(leftMask)) Thread.sleep(1);    //拿起左边的叉子
        while (!pickFork(rightMask)) Thread.sleep(1);   //拿起右边的叉子
        pickLeftFork.run();    //拿起左边的叉子 的具体执行
        pickRightFork.run();    //拿起右边的叉子 的具体执行
        while (!both.compareAndSet(1, 0)) Thread.sleep(1);    //退出临界区
        eat.run();    //吃意大利面 的具体执行
        putLeftFork.run();    //放下左边的叉子 的具体执行
        putRightFork.run();    //放下右边的叉子 的具体执行
        while (!putFork(rightMask)) Thread.sleep(1);   //放下右边的叉子
        while (!putFork(leftMask)) Thread.sleep(1);    //放下左边的叉子
    }
    private boolean pickFork(int mask) {
        int expect = fork.get();
        return (expect & mask) > 0 ? false : fork.compareAndSet(expect, expect ^ mask);
    }
    private boolean putFork(int mask) {
        int expect = fork.get();
        return fork.compareAndSet(expect, expect ^ mask);
    }
}
// 解决方案(6)
class DiningPhilosophers {
    //初始化为0, 二进制表示则为00000, 说明当前所有叉子都未被使用
    private AtomicInteger fork = new AtomicInteger(0);
    //每个叉子的int值(即二进制的00001, 00010, 00100, 01000, 10000)
    private final int[] forkMask = new int[]{1, 2, 4, 8, 16};
    public DiningPhilosophers() {
    }
    // 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 {
        int leftMask = forkMask[(philosopher + 1) % 5], rightMask = forkMask[philosopher];
        //编号为偶数的哲学家,优先拿起左边的叉子,再拿起右边的叉子
        if (philosopher % 2 == 0) {
            while (!pickFork(leftMask)) Thread.sleep(1);     //拿起左边的叉子
            while (!pickFork(rightMask)) Thread.sleep(1);    //拿起右边的叉子
        }//编号为奇数的哲学家,优先拿起右边的叉子,再拿起左边的叉子
        else {
            while (!pickFork(rightMask)) Thread.sleep(1);    //拿起右边的叉子
            while (!pickFork(leftMask)) Thread.sleep(1);     //拿起左边的叉子
        }
        pickLeftFork.run();    //拿起左边的叉子 的具体执行
        pickRightFork.run();    //拿起右边的叉子 的具体执行
        eat.run();    //吃意大利面 的具体执行
        putLeftFork.run();    //放下左边的叉子 的具体执行
        putRightFork.run();    //放下右边的叉子 的具体执行
        while (!putFork(rightMask)) Thread.sleep(1);    //放下右边的叉子
        while (!putFork(leftMask)) Thread.sleep(1);     //放下左边的叉子
    }
    private boolean pickFork(int mask) {
        int expect = fork.get();
        return (expect & mask) > 0 ? false : fork.compareAndSet(expect, expect ^ mask);
    }
    private boolean putFork(int mask) {
        int expect = fork.get();
        return fork.compareAndSet(expect, expect ^ mask);
    }
}
// 解决方案(7)
class DiningPhilosophers {
    private int[] leftFork = new int[5];
    private int[] rightFork = new int[5];
    private Object leftObj = new Object();
    private Object rightObj = new Object();
    public DiningPhilosophers() {
    }
    // 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 {
        synchronized (leftObj) {
            while (checkLeftFork(philosopher)) {
                leftObj.wait();
            }
            lockLeftFork(philosopher);
            pickLeftFork.run();
            leftObj.notifyAll();
        }
        synchronized (rightObj) {
            while (checkRightFork(philosopher)) {
                rightObj.wait();
            }
            lockRightFork(philosopher);
            pickRightFork.run();
            rightObj.notifyAll();
        }
        eat.run();
        synchronized (leftObj) {
            putLeftFork.run();
            unlockLeftFork(philosopher);
            leftObj.notifyAll();
        }
        synchronized (rightObj) {
            putRightFork.run();
            unlockRightFork(philosopher);
            rightObj.notifyAll();
        }
    }
    private void lockLeftFork(int philosopher) {
        leftFork[philosopher] = 1;
    }
    private void lockRightFork(int philosopher) {
        rightFork[philosopher] = 1;
    }
    private void unlockLeftFork(int philosopher) {
        leftFork[philosopher] = 0;
    }
    private void unlockRightFork(int philosopher) {
        rightFork[philosopher] = 0;
    }
    private boolean checkLeftFork(int philosopher) {
        return rightFork[leftPhil(philosopher)] == 1 ? true : false;
    }
    private boolean checkRightFork(int philosopher) {
        return leftFork[rightPhil(philosopher)] == 1 ? true : false;
    }
    private int leftPhil(int philosopher) {
        return (philosopher + 1) % 5;
    }
    private int rightPhil(int philosopher) {
        return (philosopher - 1 + 5) % 5;
    }
}








