Какие знаешь методы Object для concurrency?
Комментарии (1)
Ответ сгенерирован нейросетью и может содержать ошибки
Методы Object для многопоточности (Concurrency)
Класс Object в Java содержит несколько методов, которые используются для синхронизации и координации потоков. Эти методы работают в паре с synchronized блоками и мониторами.
Основные методы для многопоточности
1. wait()
Освобождает монитор объекта и ждет, пока другой поток вызовет notify() или notifyAll() на этом объекте.
public final void wait() throws InterruptedException
public final void wait(long timeoutMillis) throws InterruptedException
public final void wait(long timeoutMillis, int nanos) throws InterruptedException
// Пример: Thread ждет условия
public class WaitExample {
private boolean condition = false;
public synchronized void waitForCondition() throws InterruptedException {
while (!condition) {
wait(); // Отпускает монитор и ждет пробуждения
}
System.out.println("Condition met");
}
public synchronized void setCondition() {
condition = true;
notifyAll(); // Пробуждает все ждущие потоки
}
}
Правила использования:
- Может вызваться только внутри synchronized блока
- Освобождает lock перед ожиданием
- Должна быть while, а не if (spurious wakeups)
- Нужно ловить InterruptedException
2. notify()
Пробуждает ОДИН произвольный поток, ждущий на этом объекте.
public final void notify()
// Пример
Object lock = new Object();
Thread waiter = new Thread(() -> {
synchronized(lock) {
try {
System.out.println("Waiter: waiting...");
lock.wait();
System.out.println("Waiter: notified!");
} catch (InterruptedException e) {
e.printStackTrace();
}
}
});
Thread notifier = new Thread(() -> {
synchronized(lock) {
try {
Thread.sleep(2000);
System.out.println("Notifier: notifying...");
lock.notify(); // Пробуждает одного ждущего
} catch (InterruptedException e) {
e.printStackTrace();
}
}
});
waiter.start();
notifier.start();
Проблема: notify() пробуждает произвольный поток, может быть неправильный!
3. notifyAll()
Пробуждает ВСЕ потоки, ждущие на этом объекте.
public final void notifyAll()
// Пример: множество потребителей
public class SharedBuffer {
private Queue<String> buffer = new LinkedList<>();
public synchronized void add(String item) {
buffer.add(item);
notifyAll(); // Все потребители проверят условие
}
public synchronized String get() throws InterruptedException {
while (buffer.isEmpty()) {
wait();
}
return buffer.poll();
}
}
Когда использовать:
- Несколько потоков ждут разных условий → notifyAll()
- Один поток знает, какой поток пробудить → notify()
- Best practice: почти всегда notifyAll(), это безопаснее
4. getClass()
Возвращает объект Class объекта. Используется для синхронизации на уровне класса.
public final Class<?> getClass()
// Синхронизация на уровне класса
public class Singleton {
private static Singleton instance;
public static Singleton getInstance() {
synchronized(Singleton.class) { // Используем Class как монитор
if (instance == null) {
instance = new Singleton();
}
}
return instance;
}
}
// Проверка класса перед wait
public class ThreadUtils {
public static void waitOnClass(Class<?> clazz) throws InterruptedException {
synchronized(clazz) {
clazz.wait();
}
}
}
Полный пример: Producer-Consumer с Object методами
public class ProducerConsumerBuffer<T> {
private Queue<T> buffer = new LinkedList<>();
private int maxSize;
public ProducerConsumerBuffer(int maxSize) {
this.maxSize = maxSize;
}
// Производитель
public synchronized void produce(T item) throws InterruptedException {
// Ждем, пока буфер не освободится
while (buffer.size() == maxSize) {
System.out.println("Buffer full, producer waiting...");
this.wait(); // Отпускаем монитор
}
buffer.add(item);
System.out.println("Produced: " + item + ", size: " + buffer.size());
// Пробуждаем ждущих потребителей
this.notifyAll();
}
// Потребитель
public synchronized T consume() throws InterruptedException {
// Ждем, пока буфер заполнится
while (buffer.isEmpty()) {
System.out.println("Buffer empty, consumer waiting...");
this.wait(); // Отпускаем монитор
}
T item = buffer.poll();
System.out.println("Consumed: " + item + ", size: " + buffer.size());
// Пробуждаем ждущих производителей
this.notifyAll();
return item;
}
}
// Использование
public class Main {
public static void main(String[] args) throws InterruptedException {
ProducerConsumerBuffer<Integer> buffer = new ProducerConsumerBuffer<>(3);
// Производитель
Thread producer = new Thread(() -> {
try {
for (int i = 1; i <= 10; i++) {
buffer.produce(i);
Thread.sleep(100);
}
} catch (InterruptedException e) {
e.printStackTrace();
}
});
// Потребитель
Thread consumer = new Thread(() -> {
try {
for (int i = 0; i < 10; i++) {
buffer.consume();
Thread.sleep(200);
}
} catch (InterruptedException e) {
e.printStackTrace();
}
});
producer.start();
consumer.start();
producer.join();
consumer.join();
}
}
wait() vs notifyAll() pattern
// ✅ Правильный pattern
public synchronized void waitForCondition() throws InterruptedException {
while (!isConditionMet()) { // While, не if!
this.wait();
}
// Condition met
}
public synchronized void signalCondition() {
// Изменяем состояние
setConditionState();
// Пробуждаем ВСЕ, они проверят условие
this.notifyAll();
}
Сравнение подходов
// Старый способ (Object методы)
Object lock = new Object();
synchronized(lock) {
while (!condition) {
lock.wait();
}
// работа
lock.notifyAll();
}
// Модерный способ (java.util.concurrent.locks)
ReentrantLock lock = new ReentrantLock();
Condition condition = lock.newCondition();
lock.lock();
try {
while (!conditionMet()) {
condition.await();
}
// работа
condition.signalAll();
} finally {
lock.unlock();
}
Когда использовать Object методы:
- Legacy код
- Простая синхронизация
- Нет особых требований
Когда использовать Condition:
- Несколько условий на одном lock'е
- Нужна tryAwait с timeout
- Новый код
Распространенные ошибки
// ❌ Ошибка 1: if вместо while
public synchronized void bad() throws InterruptedException {
if (!condition) {
this.wait(); // Spurious wakeup может разбудить без условия
}
// condition может быть false!
}
// ❌ Ошибка 2: вызов wait без synchronized
public void bad2() throws InterruptedException {
this.wait(); // IllegalMonitorStateException
}
// ❌ Ошибка 3: notify() вместо notifyAll()
public synchronized void bad3() {
this.notify(); // Может пробудить неправильный поток
}
// ✅ Правильно
public synchronized void correct() throws InterruptedException {
while (!condition) {
this.wait();
}
// work
this.notifyAll();
}
Заключение
Объект методы wait()/notify()/notifyAll() — это основа синхронизации потоков в Java. Хотя есть более современные инструменты (Condition, CountDownLatch, Semaphore), понимание этих методов критично для понимания многопоточности в Java.