Исключение IllegalMonitorStateException возникает, даже если поток содержит объект ReentrantLock

#illegalstateexception

#исключение illegalstateexception

Вопрос:

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

Автор вошел в критическую секцию! Сообщение: оставайтесь сильными, удерживая блокировку боли! Исключение в потоке «Writer» java.lang.Исключение IllegalMonitorStateException в java.lang.Object.notifyAll(собственный метод)

 public class Buffer {
    private StringBuilder text;
    private final int MAX_PERMITS;
    private ReentrantLock writerLock = new ReentrantLock();
    private Semaphore semaphore;

    public Buffer(int maxPermits) {
        text = new StringBuilder();
        MAX_PERMITS = maxPermits;
        semaphore = new Semaphore(MAX_PERMITS);
    }

    public void write(String message) throws InterruptedException {
        writerLock.lock();
        System.out.println(ANSI_BLUE   Thread.currentThread().getName()   " has entered the critical section! Message: "   message);
        text.append(message); text.append(". ");
        Thread.sleep(2000);

        if(writerLock.isHeldByCurrentThread()) {
            System.out.println(ANSI_BLUE "Lock held!");
            writerLock.notifyAll();
        }
        writerLock.unlock();
    }
    public void read() throws InterruptedException{
        if(text.length()==0) return;
        writerLock.lock();
        semaphore.acquire();
        System.out.println(ANSI_GREEN Thread.currentThread().getName() " read the following message: " text.toString());
        semaphore.release();
        writerLock.unlock();
    }
}
 

Ответ №1:

Явные блокировки, такие как ReentrantLock, по сути, являются отдельным типом блокировки для неявных «синхронизированных» блокировок. Другими словами, блокировка / разблокировка ReentrantLock — это отдельная схема для схемы synchronized / wait / notify. Поэтому вам нужно решить, какую схему вы хотите использовать:

  • При явной блокировке вам нужно создать условие для блокировки (см. Метод Lock.NewCondition() ), затем использовать signal() и await() для условия.
  • При неявной блокировке перед вызовом функции wait() / notify() вам необходимо выполнить синхронизацию с данным объектом, чтобы получить блокировку

Проблема с вашим кодом, по сути, заключается в том, что вы пытаетесь «смешивать и сопоставлять» между двумя схемами.

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

Недостатки неявной синхронизированной блокировки включают в себя:

  • для каждого объекта есть только один из них, поэтому в вашем коде может быть менее ясно, почему вы на самом деле ожидаете / уведомляете;
  • синхронизированные блокировки по сути являются «первым входом, первым выходом», поэтому потоки, которые захватывают блокировку, могут долгое время лишать другие потоки возможности ее получения.