Chandy/Misra解法[编辑]
1984年,K. Mani Chandy和J. Misra提出了哲学家就餐问题的另一个解法,允许任意的用户(编号P1, …, Pn)争用任意数量的资源。与资源分级解法不同的是,这里编号可以是任意的。
- 对每一对竞争一个资源的哲学家,新拿一个餐叉,给编号较低的哲学家。每只餐叉都是“干净的”或者“脏的”。最初,所有的餐叉都是脏的。
- 当一位哲学家要使用资源(也就是要吃东西)时,他必须从与他竞争的邻居那里得到。对每只他当前没有的餐叉,他都发送一个请求。
- 当拥有餐叉的哲学家收到请求时,如果餐叉是干净的,那么他继续留着,否则就擦干净并交出餐叉。
- 当某个哲学家吃东西后,他的餐叉就变脏了。如果另一个哲学家之前请求过其中的餐叉,那他就擦干净并交出餐叉。
- 这个解法允许很大的并行性,适用于任意大的问题。
下面是java 的实现
package Philosopher.ChandyMisra;
import java.util.Random;
import java.util.concurrent.Executor;
import java.util.concurrent.ExecutorService;
import java.util.concurrent.Executors;
/**
* Created by zhensheng on 2016/10/18.
*/
class Stick {
int owner;
boolean dirty;
int number;
public synchronized void setStatus(boolean status){
dirty = status;
}
public synchronized boolean getStatus(){
return this.dirty;
}
public synchronized void setOwner(int owner){
this.owner = owner;
}
public synchronized int getOwner(){
return owner;
}
public Stick(boolean dirty, int number) {
this.dirty = dirty;
this.number = number;
}
}
public class Philo implements Runnable {
Stick leftStick, rightStick;
Philo leftPhilo, rightPhilo;
int number, eatTimes;
//DinningPhi dinningExam;
//Thread t;
public Philo(int number, int eatTimes) {
this.number = number;
this.eatTimes = eatTimes;
}
public void eating(){
try{
Thread.sleep(3000);
}catch(InterruptedException ie){
System.out.println("Catch an Interrupted Exception!");
return;
}
leftStick.setStatus(true);
rightStick.setStatus(true);
eatTimes++;
System.out.println("Philo "+ number + "is eating " + ": "+ eatTimes );
//dinningExam.repaint();
}
public boolean answer(Stick used){
boolean retFlag = false;
synchronized(this){
if(used.getStatus()){
if(used == leftStick)
used.setOwner(leftPhilo.number);
else if(used == rightStick)
used.setOwner(rightPhilo.number);
else{
System.out.println("Error status!");
retFlag = false;
}
used.setStatus(false);
retFlag = true;
}
else
retFlag = false;
}
if(retFlag)
System.out.println("Philo "+ number + "request success!" );
//dinningExam.repaint();
return retFlag;
}
@Override
public void run() {
Random r = new Random();
int intR;
while(true){
while(leftStick.getOwner() != number | rightStick.getOwner() != number){
intR = r.nextInt();
if(intR % 2 == 0 && leftStick.getOwner() != number)
leftPhilo.answer(leftStick);
else if(intR % 2 == 1 && rightStick.getOwner() != number)
rightPhilo.answer(rightStick);
}
synchronized(this){
if(leftStick.getOwner() == number
&& rightStick.getOwner() == number){
eating();
}
}
try{
int sleepSec = r.nextInt();
if(sleepSec < 0)
sleepSec = -sleepSec;
Thread.sleep(sleepSec % 500);
}catch(InterruptedException ie){
System.out.println("Catch an Interrupted Exception!");
}
}
}
public static void main(String[] args) {
ExecutorService exec = Executors.newCachedThreadPool();
Philo[] ps = new Philo[5];
Stick[] ss = new Stick[5];
for (int i = 0; i < 5 ; i++) {
ss[i] = new Stick(true, i);
ps[i]= new Philo(i,0);
}
System.out.println((0-1)%5);
for (int i = 0; i < 5; i++) {
ps[i].leftPhilo= ps[(i+4)%5];
ps[i].rightPhilo= ps[(i+1)%5];
ps[i].leftStick = ss[i];
ps[i].rightStick=ss[(i+1)%5];
}
for (int i = 0; i < 5; i++) {
exec.execute(ps[i]);
}
exec.shutdown();
}
}
output
Philo 2request success!
Philo 2request success!
Philo 3request success!
Philo 3request success!
Philo 0is eating : 1
Philo 0request success!
Philo 0request success!
Philo 1is eating : 1
Philo 4is eating : 1
Philo 1request success!
Philo 4request success!
Philo 1request success!
Philo 4request success!
Philo 3is eating : 1
Philo 0is eating : 2
Philo 3request success!
...