Зачем нужен метод wait() из класса Object?
Комментарии (1)
Ответ сгенерирован нейросетью и может содержать ошибки
Зачем нужен метод wait() из класса Object
Метод wait() — это фундаментальный инструмент для синхронизации потоков в Java, предназначенный для реализации паттерна "производитель-потребитель" и других механизмов взаимодействия между потоками.
Основное назначение
Метод wait() позволяет потоку добровольно освободить блокировку монитора и перейти в состояние ожидания до тех пор, пока другой поток не вызовет notify() или notifyAll() на том же объекте. Это критически важно для избежания активного ожидания (busy-waiting) и использования ЦПУ в пустую.
Механизм работы
synchronized(monitor) {
while(!condition) {
monitor.wait(); // Поток освобождает блокировку и ждёт
}
// Поток пробуждён, переотвоена блокировка, выполняется код
performAction();
}
Важные моменты:
wait()ДОЛЖЕН вызываться только внутриsynchronizedблокаwait()освобождает мьютекс/монитор перед ожиданием- При пробуждении поток должен заново закупить блокировку
- Другие потоки могут использовать блокировку в это время
Три версии метода
// Бесконечное ожидание до вызова 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() напрямую.