5

我正在尝试在餐饮哲学家问题中学习信号量的基本要点。现在,我有一个 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;
    }
}

holder 变量用于我不确定是否需要的函数:

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");

例如,我的程序确实输出“哲学家 0 吃完饭”,然后继续执行。另外两行从不输出,所以很明显我发布的方式有问题。

任何帮助表示赞赏。

4

5 回答 5

8

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

于 2009-03-03T16:30:07.527 回答
1

问题是当thread1有一个特定的筷子并且另一个试图得到相同的筷子时,它会take()在线等待-methodthis.lock.acquire();但它不会释放对象本身的监视器。

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

于 2009-03-03T16:33:53.930 回答
1

您既要锁定筷子又要让它持有大小为 1 的信号量,这似乎有点令人困惑。通常,信号量提供资源的票证,如果您只有一张票证,这实际上是互斥,与锁相同(同步块或 Lock 对象)。您可能会考虑让 Chopstick 成为锁定对象本身。

如果您有兴趣,我在不久前写了一篇关于用 Java 就餐哲学家的博客文章,尽管它实际上是关于如何通过使用其他策略来避免死锁。

于 2009-03-03T16:48:45.953 回答
1

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

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){}
}

}

于 2016-11-26T20:55:37.793 回答
0

Philospher 需要在开始进食之前锁定两个筷子,并且会先拾取 leftone,然后等待正确的所以开始进食,因此 start 方法应该同步。以下方法将使其工作:

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

public void finishEating(int id) {
    leftChopstick.release();
    rightChopstick.release();
}
于 2013-11-27T11:12:55.247 回答