我正在寻找一种使用信号量来解决餐饮哲学家问题的方法,我完全不知道应该如何去做。我在下面提供了我的代码。
class ChopStick{
private int count;
private boolean inuse;
Lock lock = new ReentrantLock();
Condition notInUse = lock.newCondition();
public ChopStick(){
inuse = false;
}
public void pickUp(){
lock.lock();
try{
while(inuse){
try{
notInUse.await();
}catch(InterruptedException e){}
}
inuse = true;
}finally{lock.unlock();}
}
public void putDown(){
lock.lock();
try{
inuse = false;
notInUse.signal();
}finally{lock.unlock();}
}
}
class Philosopher extends Thread{
Semaphore sem;
private ChopStick ch1,ch2; //chopsticks
private int phil; //philosopher id
public Philosopher(int p, ChopStick left, ChopStick right, Semaphore s){
phil = p;
ch1 = left;
ch2 = right;
sem = s;
}
public void run() {
while(true){
try {
sem.acquire();
} catch (InterruptedException e) {}
think(phil);
//pickup chopsticks
ch1.pickUp();
ch2.pickUp();
eat(phil);
//putdown chopsticks
ch1.putDown();
ch2.putDown();
sem.release();
}
}
我想到哲学家何时使用sem.acquire()
拿起筷子然后当他们使用sem.release()
时,但我不确定这是否正确。是吗?
编辑所以我已经实现了这一点。它似乎有效,但我不确定。
class ChopStick{
private Semaphore sem;
public ChopStick(Semaphore s){
sem = s;
}
public void pickUp(){
try{
sem.acquire();
}catch(InterruptedException e){}
}
public void putDown(){
sem.release();
}
答案 0 :(得分:4)
我建议在Philosopher
上添加一个信号量,而不是在Chopstick
上放置信号量; Philosopher
来电获取左右筷子'信号量和释放筷子'信号量完成后。这将取代ReentrantLock
上的Chopstick
。
为防止死锁,您可以使用tryAcquire(int permits, long timeout, TimeUnit unit)
,以便Philosopher
释放其左筷子的信号量,如果它无法在超时内获取其正确的筷子的信号量;如果您使用随机超时(例如在100到500毫秒之间),那么每个Philosopher
最终都应该取得进展。
编辑:您的新Chopstick
代码存在死锁风险 - 所有哲学家都拿起他们的左筷子然后等待他们的正确筷子自由。 tryAcquire
允许哲学家释放其左筷子,如果它在超时后无法获得正确的筷子,这将允许哲学家向左移动。
class ChopStick{
private static Random random = new Random();
// initialize with one permit
private Semaphore sem = new Semaphore(1);
public boolean pickUp(){
try {
// wait between 100 and 500 milliseconds
return sem.tryAcquire(1, random.nextInt(400) + 100, TimeUnit.MILLISECONDS);
} catch(InterruptedException e) {
return false;
}
}
public void putDown(){
sem.release();
}
}
class Philosopher extends Thread {
public void run() {
while(true){
think(phil);
doEat();
}
private void doEat() {
if(ch1.pickup()) {
if(ch2.pickup()) {
eat(phil);
ch1.release();
ch2.release();
else {
ch1.release();
doEat();
}
else {
doEat();
}
}
}