Вопрос

Я пытаюсь изучить основную суть проблемы семафора в задаче «Обедающий философ».Прямо сейчас у меня есть массив класса Chopstick, и каждая Chopstick имеет семафор с одним доступным разрешением:

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

Моя программа, например, выводит «Философ 0 закончил есть» и продолжает выполнение.Две другие строки никогда не выводятся, поэтому очевидно, что что-то не так с тем, как я отпускаю.

Любая помощь приветствуется.

Это было полезно?

Решение

Я бы удалил ключевое слово «синхронизировано» из сигнатур вашего метода.Вы используете внешний механизм блокировки (в данном случае семафор).Ключевое слово «синхронизировано» пытается получить блокировки, используя собственный мьютекс объекта.Сейчас вы блокируете два ресурса, которые, как я подозреваю, могут вызывать тупик.

Другие советы

Проблема в том, что когда у потока 1 есть определенная палочка для еды, а другой пытается получить ту же самую, он будет ждать в take()-метод онлайн this.lock.acquire(); но это будет НЕТ отпустите монитор на самом объекте.

Если теперь поток 1 попытается выпустить палочку, он не сможет войти в release()-метод, поскольку он все еще заблокирован другим потоком, ожидающим take().Это тупик

Кажется немного запутанным, что вы одновременно фиксируете палочку для еды и держите в ней семафор размера 1.Обычно семафор предоставляет билеты для ресурса, и если у вас есть только один билет, это фактически взаимное исключение, идентичное блокировке (либо синхронизированному блоку, либо объекту блокировки).Вы можете подумать о том, чтобы сделать Chopstick самим объектом блокировки.

Некоторое время назад я сделал сообщение в блоге об обедающих философах на Java, если вам интересно, хотя на самом деле речь идет о том, как избежать тупика, используя другие стратегии.

Убедитесь, что не используется какое-либо ключевое слово блокировки или синхронизации.Приведенный ниже код для палочки для еды у меня отлично работает.Не профессионал, но должен дать вам некоторое представление;

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

}

Прежде чем начать есть, Филосферу необходимо захватить обе палочки, и он сначала возьмет левую, а затем подождет правую, поэтому начните есть, поэтому метод запуска должен быть синхронизирован.Следующие методы заставят его работать:

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

public void finishEating(int id) {
    leftChopstick.release();
    rightChopstick.release();
}
Лицензировано под: CC-BY-SA с атрибуция
Не связан с StackOverflow
scroll top