← Назад к вопросам

Зачем нужен метод wait() из класса Object?

2.2 Middle🔥 151 комментариев
#Многопоточность

Комментарии (1)

🐱
claude-haiku-4.5PrepBro AI22 мар. 2026 г.(ред.)

Ответ сгенерирован нейросетью и может содержать ошибки

Зачем нужен метод wait() из класса Object

Метод wait() — это фундаментальный инструмент для синхронизации потоков в Java, предназначенный для реализации паттерна "производитель-потребитель" и других механизмов взаимодействия между потоками.

Основное назначение

Метод wait() позволяет потоку добровольно освободить блокировку монитора и перейти в состояние ожидания до тех пор, пока другой поток не вызовет notify() или notifyAll() на том же объекте. Это критически важно для избежания активного ожидания (busy-waiting) и использования ЦПУ в пустую.

Механизм работы

synchronized(monitor) {
    while(!condition) {
        monitor.wait();  // Поток освобождает блокировку и ждёт
    }
    // Поток пробуждён, переотвоена блокировка, выполняется код
    performAction();
}

Важные моменты:

  1. wait() ДОЛЖЕН вызываться только внутри synchronized блока
  2. wait() освобождает мьютекс/монитор перед ожиданием
  3. При пробуждении поток должен заново закупить блокировку
  4. Другие потоки могут использовать блокировку в это время

Три версии метода

// Бесконечное ожидание до вызова notify()
void wait() throws InterruptedException

// Ожидание с таймаутом (в миллисекундах)
void wait(long timeoutMillis) throws InterruptedException

// Ожидание с таймаутом и наносекундной точностью
void wait(long timeoutMillis, int nanos) throws InterruptedException

Практический пример: Паттерн Производитель-Потребитель

class Buffer {
    private Queue<Integer> queue = new LinkedList<>();
    private final int capacity = 10;
    
    public synchronized void produce(int item) throws InterruptedException {
        while(queue.size() == capacity) {
            wait();  // Ждём, пока потребитель освободит место
        }
        queue.offer(item);
        notifyAll();  // Пробуждаем потребителей
    }
    
    public synchronized int consume() throws InterruptedException {
        while(queue.isEmpty()) {
            wait();  // Ждём, пока производитель что-то добавит
        }
        int item = queue.poll();
        notifyAll();  // Пробуждаем производителей
        return item;
    }
}

Почему важно использовать wait() вместо цикла с sleep()

// Плохо - активное ожидание (busy-waiting)
synchronized(lock) {
    while(!condition) {
        Thread.sleep(100);  // Тратит ЦПУ на проверку каждые 100ms
    }
}

// Хорошо - правильное ожидание
synchronized(lock) {
    while(!condition) {
        lock.wait();  // Пробуждается сразу когда условие выполнено
    }
}

Важные особенности

  • Spurious wakeup — поток может пробудиться без вызова notify(). Поэтому всегда используй цикл while, а не if
  • InterruptedException — может быть выброшено, если поток прерван во время ожидания
  • notify() vs notifyAll() — notify() пробуждает один случайный поток, notifyAll() пробуждает все ждущие потоки

Современные альтернативы

Для новых проектов рекомендуется использовать конструкции из пакета java.util.concurrent:

CountDownLatch, CyclicBarrier, Semaphore, BlockingQueue

Они предоставляют более удобный и безопасный способ синхронизации без необходимости работать с wait() и notify() напрямую.

Зачем нужен метод wait() из класса Object? | PrepBro