餐饮哲学家在Java中的信号量问题

时间:2009-03-03 16:27:51

标签: java multithreading locking semaphore

我正在努力学习餐饮哲学家问题中信号量的基本要点。现在,我有一个类Chopstick,每个Chopstick都有一个信号量,有1个可用的许可证:

public class Chopstick
{
    Thread holder = null;
    private Semaphore lock = new Semaphore(1);

    public synchronized void take() throws InterruptedException
    {
        this.lock.acquire();
        holder = Thread.currentThread();

    }

    public synchronized void release()
    {   
        this.lock.release();
        holder = null;
    }
}

持有人变量用于我不确定需要的功能:

public synchronized void conditionalRelease()
{
    if (holder == Thread.currentThread())
    {
        holder = null;
        this.lock.release();
    }
}

该程序编译并运行,但似乎在释放筷子时遇到一些麻烦。有时,筷子会被释放,有时则不会。当他们不释放时,当所有的筷子被拿走并且一个哲学家饿了时,程序最终会挂断。

这是Philosopher类中的代码,用于在随机的时间之后释放筷子:

System.out.println(this.name + " is eating");
Thread.sleep(this.getRandTime());
System.out.println(this.name + " has finished eating");

rightChopstick.release();
System.out.println(this.name + " has released the right chopstick");
leftChopstick.release();
System.out.println(this.name + " has released the left chopstick");

例如,我的程序输出“Philosopher 0吃完了”,然后继续执行。其他两行从不输出,所以我发布的方式显然有些不对。

感谢任何帮助。

5 个答案:

答案 0 :(得分:8)

我会从您的方法签名中取出'synchronized'关键字。您正在使用外部锁定机制(在本例中为信号量)。 'synchronized'关键字试图使用对象自己的互斥锁获取锁。您现在锁定了2个我怀疑可能导致死锁的资源。

答案 1 :(得分:1)

问题在于,当thread1有一个特定的筷子而另一个试图获得相同的筷子时,它会在take() - 方法上等待this.lock.acquire();,但它会释放对象本身的监视器。

如果现在thread1尝试释放筷子,它就无法进入release() - 方法,因为它仍然被等待take()的其他线程锁定。这是一个僵局

答案 2 :(得分:1)

看起来有点令人困惑的是你要锁定筷子并让它持有大小为1的信号量。通常信号量提供资源的门票,如果你只有一张票,那么这实际上是相互排斥的,这与锁(同步块或锁定对象)。您可能会考虑实际上将Chopstick作为锁定对象本身。

如果你感兴趣的话,我曾经在Java上写过一篇关于Java的餐饮哲学家的博客文章,尽管它确实是关于如何通过使用其他策略来避免死锁。

答案 3 :(得分:1)

确保没有使用任何锁定或synchronized关键字。筷子下面的代码对我来说很好。不是专业人士,但必须给你一些想法;

public class Chopstick {
private boolean inuse;
Semaphore sem;

public Chopstick(){

    inuse = false;
    sem = new Semaphore(1);
}
public void pickUp()
{
    try
    {
        while(inuse)
        {
            try
            {
                sem.acquire();

            }
            catch(InterruptedException e) {}
        }
        inuse = true;
    }catch(Exception e){}
}
public void putDown()
{
    try
    {
        inuse = false;
        sem.release();

    }
    catch (Exception e){}
}

}

答案 4 :(得分:0)

Philospher在开始进食之前需要锁定两个chosticks并且先将leftone先取出然后等待,所以开始进食所以start方法应该同步。 以下方法将使其工作:

public synchronized void startEating() {
    leftChopstick.acquire();
    rightChopstick.acquire();
}

public void finishEating(int id) {
    leftChopstick.release();
    rightChopstick.release();
}