Комментарии (1)
Ответ сгенерирован нейросетью и может содержать ошибки
У всех объектов есть монитор
В Java каждый объект имеет встроенный монитор (англ. monitor), который используется для синхронизации и управления доступом к ресурсам в многопоточной среде. Это фундаментальная часть модели параллелизма Java.
Что такое монитор
Монитор — это механизм, который гарантирует, что только один поток может одновременно выполнять синхронизированный код для конкретного объекта. Он включает:
- Блокировку (Lock) — контролирует доступ
- Очередь ожидания — потоки, ожидающие доступа
- Условные переменные — для взаимодействия потоков
Как использовать монитор
1. Синхронизированные методы
public class BankAccount {
private int balance = 1000;
// Весь метод защищен монитором объекта
public synchronized void withdraw(int amount) {
if (balance >= amount) {
balance -= amount;
System.out.println("Withdrawn: " + amount);
}
}
public synchronized int getBalance() {
return balance;
}
}
// Использование
BankAccount account = new BankAccount();
account.withdraw(100); // Потокобезопасно
За кулисами это эквивалентно:
public void withdraw(int amount) {
// Автоматически вызывается monitorenter
synchronized (this) {
if (balance >= amount) {
balance -= amount;
}
}
// Автоматически вызывается monitorexit
}
2. Синхронизированные блоки
public class ThreadSafeCounter {
private int count = 0;
private final Object lock = new Object();
public void increment() {
// Защищаем только критическую секцию
synchronized (lock) {
count++;
}
}
public int getCount() {
synchronized (lock) {
return count;
}
}
}
Монитор на уровне класса
У классов (объектов типа Class) также есть свой монитор:
public class Singleton {
private static Singleton instance = null;
// Синхронизированный статический метод
// Использует монитор объекта Singleton.class
public static synchronized Singleton getInstance() {
if (instance == null) {
instance = new Singleton();
}
return instance;
}
}
// Эквивалентно:
public static Singleton getInstance() {
synchronized (Singleton.class) {
if (instance == null) {
instance = new Singleton();
}
}
return instance;
}
Взаимодействие потоков через монитор
Методы wait(), notify(), notifyAll() работают с монитором:
public class ProducerConsumer {
private final List<String> queue = new ArrayList<>();
private final int MAX_SIZE = 5;
public synchronized void produce(String item) throws InterruptedException {
// Ждём, пока очередь не опустеет
while (queue.size() >= MAX_SIZE) {
wait(); // Освобождает монитор и ждёт
}
queue.add(item);
System.out.println("Produced: " + item);
notifyAll(); // Пробуждает ожидающие потоки
}
public synchronized String consume() throws InterruptedException {
while (queue.isEmpty()) {
wait();
}
String item = queue.remove(0);
System.out.println("Consumed: " + item);
notifyAll();
return item;
}
}
Что можно и нельзя синхронизировать
Можно синхронизировать:
- Любой объект (String, Integer, пользовательский класс)
- Класс через его Class объект
Нельзя синхронизировать:
- Примитивные типы (int, double, boolean)
- null — вызовет NullPointerException
public class Example {
private int counter; // Примитив
private Integer wrapper; // Объект — можно
public synchronized void badSync() {
// synchronized работает на объектах, не на примитивах
counter++; // Не защищено синхронизацией
}
}
Углубленная информация: HotSpot оптимизации
JVM автоматически оптимизирует мониторы:
- Biased Locking — если поток один, блокировка бесплатна
- Lightweight Locking — при конфликте переходит на более тяжелую
- Heavyweight Locking — системная блокировка (mutex)
public class OptimizedMonitor {
private int value;
public synchronized int getValue() {
return value; // HotSpot может оптимизировать
}
}
Современные альтернативы
Для сложных сценариев используют:
import java.util.concurrent.locks.*;
public class ModernLocking {
private final ReentrantLock lock = new ReentrantLock();
private int balance = 1000;
public void withdraw(int amount) {
lock.lock();
try {
if (balance >= amount) {
balance -= amount;
}
} finally {
lock.unlock();
}
}
}
И атомарные переменные:
import java.util.concurrent.atomic.*;
public class AtomicCounter {
private final AtomicInteger counter = new AtomicInteger(0);
public void increment() {
counter.incrementAndGet(); // Не требует synchronized
}
}
Монитор — это основа многопоточности в Java, и понимание его работы критично для написания безопасного кода.