0
点赞
收藏
分享

微信扫一扫

LeetCode(多线程)- 1226. 哲学家进餐


题目链接:​​点击打开链接​​

题目大意:略。

解题思路

位运算难点理解(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;
}
}


举报

相关推荐

0 条评论