Java 中的信号量问题与哲学家就餐

发布于 2024-07-14 09:35:26 字数 1258 浏览 8 评论 0原文

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

例如,我的程序确实输出“Philosopher 0 已吃完饭”,然后继续执行。 另外两行从未输出,所以显然我的释放方式有问题。

任何帮助表示赞赏。

I'm trying to learn the basic jist of a Semaphore in the Dining Philosopher problem. Right now, I have an array of class Chopstick, and each Chopstick has a semaphore with 1 available permit:

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;
    }
}

The holder variable is used for a function that I am not sure I need:

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

The program compiles and runs, but seems to have some trouble releasing the chopsticks. Sometimes, the chopsticks get released, sometimes they don't. When they don't release, the program eventually hangs up when all of the chopsticks are taken and one philosopher is hungry.

Here is the code within the Philosopher class to release the chopstick after a random amount of time:

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

My program does output "Philosopher 0 has finished eating", for example, and continues execution. The other two lines never output, so obviously something is wrong with the way I am releasing.

Any help is appreciated.

如果你对这篇内容有疑问,欢迎到本站社区发帖提问 参与讨论,获取更多帮助,或者扫码二维码加入 Web 技术交流群。

扫码二维码加入Web技术交流群

发布评论

需要 登录 才能够评论, 你可以免费 注册 一个本站的账号。

评论(5

违心° 2024-07-21 09:35:27

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

I would take the 'synchronized' keyword out of your method signatures. You're using an external locking mechanism (the semaphore, in this case). The 'synchronized' keyword is trying to get locks using the object's own mutex. You are now locking on 2 resources which I suspect might be causing a deadlock.

-黛色若梦 2024-07-21 09:35:27

问题是,当线程 1 有一把特定的筷子,而另一个线程尝试获取相同的筷子时,它将在 this.lock.acquire();take() 方法中等待code> 但它不会释放对象本身的监视器。

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

The problem is that when thread1 has a specific chopstick and another tries to get the same one it will wait in the take()-method on line this.lock.acquire(); but it will NOT release the monitor on the object itself.

If now thread1 tries to release the chopstick it can not enter the release()-method since it's still locked by the other thread waiting in take(). That's a deadlock

寂寞花火° 2024-07-21 09:35:27

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

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

It seems a little confusing that you are both locking on the chopstick and having it hold a semaphore of size 1. Generally a semaphore provides tickets to a resource and if you have only one ticket, that's effectively mutual exclusion which is identical to a lock (either a synchronized block or a Lock object). You might consider actually making the Chopstick the lock object itself.

I did a blog post on the dining philosophers in Java a while back if you're interested, although it's really about how to avoid deadlock by using other strategies.

压抑⊿情绪 2024-07-21 09:35:27

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

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

}

Make sure there is no any locking or synchronised keyword used. The code below for the chop stick works fine for me.. Not a pro but must give u some idea;

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

}

听你说爱我 2024-07-21 09:35:27

哲学家需要在开始吃东西之前获得对两只筷子的锁定,并且会先拿起左边的筷子,然后等待右边的筷子,然后开始吃饭,因此开始方法应该同步。
以下方法将使其发挥作用:

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

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

Philospher needs to acquire lock on both chosticks before start eating and will pickup leftone first then wait for right so start eating so start method should be synchronised.
Following methods will make it work:

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

public void finishEating(int id) {
    leftChopstick.release();
    rightChopstick.release();
}
~没有更多了~
我们使用 Cookies 和其他技术来定制您的体验包括您的登录状态等。通过阅读我们的 隐私政策 了解更多相关信息。 单击 接受 或继续使用网站,即表示您同意使用 Cookies 和您的相关数据。
原文