ПРИХОДИТЕ УЧИТЬСЯ НОВОЙ ПРОФЕССИИ ЛЕТОМ СО СКИДКОЙ ДО 70%Забронировать скидку

Решение ошибки IllegalMonitorStateException в Java: wait()

Пройдите тест, узнайте какой профессии подходите и получите бесплатную карьерную консультацию
В конце подарим скидку до 55% на обучение
Я предпочитаю
0%
Работать самостоятельно и не зависеть от других
Работать в команде и рассчитывать на помощь коллег
Организовывать и контролировать процесс работы

Быстрый ответ

Для предотвращения выброса исключения IllegalMonitorStateException, необходимо вызывать метод wait() из синхронизированного контекста, связанного с объектом-монитором. То есть, поток должен захватить монитор объекта, чего можно достичь с использованием синхронизированного блока или метода:

Java
Скопировать код
synchronized (object) {
    while (!condition) {
        object.wait(); // Время отдохнуть! 💤
    }
    // Пора просыпаться и продолжить работу.
}

Обратите внимание, что object.wait() необходимо выполнять в контексте synchronized (object), чтобы избежать преждевременного пробуждения.

Пройдите тест и узнайте подходит ли вам сфера IT
Пройти тест

Особенности работы с потоками и многозадачностью

Пользование конкурентными утилитами

Забудьте о сложностях ручной синхронизации. Классы и методы из пакета java.util.concurrent представляют собой уровень абстракции более высокого порядка, который способствует упрощению работы в многопоточном окружении и позволяет снизить вероятность ошибок. Например, ReentrantLock и Condition из пакета java.util.concurrent.locks помогут управлять взаимными блокировками и условиями:

Java
Скопировать код
ReentrantLock lock = new ReentrantLock();
Condition condition = lock.newCondition();

lock.lock(); // Теперь я держу ситуацию под контролем! 💪
try {
    while (!happyHour()) { // Время выпить еще не пришло?
        condition.await();
    }
    // Наступил час расслабиться с пивом! 🍺
} finally {
    lock.unlock(); // Не забудем освободить ресурсы для других! 😌
}

CountDownLatch: более удобный вариант

CountDownLatch работает по принципу обратного отсчета. Его можно представить как потоки, которые ожидают выполнения определенной задачи. Он отлично подойдет для случаев, когда нужно дождаться окончания нескольких событий:

Java
Скопировать код
CountDownLatch latch = new CountDownLatch(1);

// Поток в режиме ожидания
latch.await(); // Мы уже прибыли?

// Поток, сигнализирующий о завершении
latch.countDown(); // Стартуем! 🚀

Как избежать частых ошибок

Использовать объекты типа Thread в качестве блокировок не рекомендуется, так как это может создавать побочные эффекты. Вместо этого выбирайте подходящие классы или примитивы для управления блокировками, чтобы обеспечить корректную работу вашего кода.

Визуализация

Добро пожаловать в синхронизированный ресторан Java! 🍴

Markdown
Скопировать код
Поток 1 (🧑): "Регистрация пройдена. Ищу свободное место 🪑."
Поток 2 (👩): "Регистрация пройдена. Ищу свободное место 🪑."

Гости могут вызвать официанта только после того, как займут место:

Java
Скопировать код
synchronized(seat) {
    // Присел на место! ('seat' это объект-монитор)
    seat.wait(); // Официант, где мой заказ? 😄
}

Попытка вызвать официанта, не заняв место, будет считаться недопустимой:

Java
Скопировать код
// Место не занято
seat.wait(); // 🚨 IllegalMonitorStateException! 🚨

Места (🪑) здесь выступают в роли ключа к монитору. Перед тем, как вызвать wait(), обязательно захватите этот ключ! В противном случае обслуживания вы не получите!

Пробудите ваши потоки!

При ожидающих потоках всегда проверяйте условие в цикле while:

Java
Скопировать код
synchronized (object) {
    while (!coffeeReady()) {
        object.wait(); // Ждем кофе! ☕ 
    }
    // Кофе готов! Пришло время наслаждаться.
}

Ключ к успеху – читаемый код

Выбирайте именованные классы для ваших поточных операций, ведь от этого зависит простота чтения и отладки кода.

Не изобретайте колесо заново

Не стоит затруднять свою жизнь, создавая собственные решения для обеспечения поточной безопасности, особенно когда есть уже готовые, такие как ConcurrentHashMap или CopyOnWriteArrayList. Они включают все необходимые механизмы для предотвращения условий гонки.

Полезные материалы

  1. Object (Java Platform SE 8) — официальная документация Java по методу wait().
  2. Synchronization (The Java™ Tutorials) — учебные материалы по теме синхронизации и работе с методом wait().
  3. IllegalMonitorStateException (Java Platform SE 8) — подробное описание исключения IllegalMonitorStateException.
  4. Thread Signaling — примеры применения методов wait и notify.
  5. Synchronization in Java – GeeksforGeeks — статья о методах wait, notify и механизме синхронизации в Java.
  6. Java concurrency (multi-threading) – Tutorial — подробное руководство по координации работы потоков в Java.