Ответ
Монитор — это механизм синхронизации, встроенный в каждый объект Java, который обеспечивает взаимное исключение (mutual exclusion) для критических секций кода.
Как это работает:
- У каждого объекта (
Object) есть связанный с ним монитор (или встроенная блокировка). - Ключевое слово
synchronizedиспользуется для захвата монитора объекта. - Только один поток в один момент времени может владеть монитором конкретного объекта и выполнять код в
synchronizedблоке или методе для этого объекта. - Остальные потоки, пытающиеся войти в синхронизированную секцию для того же объекта, блокируются и помещаются в entry set (очередь ожидания монитора).
Реализация:
// 1. Синхронизированный метод (монитором выступает экземпляр класса 'this')
public class SharedCounter {
private int count = 0;
public synchronized void increment() {
count++; // Критическая секция защищена монитором 'this'
}
}
// 2. Синхронизированный блок с явным указанием объекта-монитора
public class SharedResource {
private final Object lock = new Object(); // Специальный объект для монитора
private int data;
public void updateData(int value) {
// Несинхронизированная работа...
synchronized (lock) { // Захват монитора объекта 'lock'
data = value; // Критическая секция
}
}
}
Важные особенности монитора в Java:
- Реентерабельность (Reentrancy): Поток, уже владеющий монитором, может повторно входить в синхронизированные блоки по тому же монитору (счётчик вхождений увеличивается). Это предотвращает самоблокировку (self deadlock).
- wait(), notify(), notifyAll(): Методы класса
Object, которые позволяют потокам координировать работу. Поток, владеющий монитором, может вызватьwait(), чтобы освободить монитор и перейти в wait set. Другой поток, вызвавnotify()/notifyAll(), может разбудить ожидающие потоки.
Монитор — это базовая, встроенная в JVM реализация мьютекса с дополнительными возможностями для координации потоков.
Ответ 18+ 🔞
Давай я тебе на пальцах объясню, что за хуйня этот монитор в Java, а то в учебниках пишут так, что мозги набок выворачивает.
Представь себе сортир в общаге, один на весь этаж. Вот этот сортир — это и есть объект. А монитор — это та самая хреновина на двери, засов такой. Пока засов задвинут изнутри — дверь не открывается, все довольны.
Как эта ебля работает:
- У каждого объекта, даже у самого простого
new Object(), с завода вшит этот самый засов (монитор). - Ключевое слово
synchronized— это как крикнуть «ЗАНЯТО!» и щёлкнуть этим засовом. - Только один чувак может сидеть в сортире и делать свои дела. Остальные стоят в коридоре, чешут репу и ждут своей очереди (это и есть entry set).
- Как только первый выходит и засов щёлкает — следующий заскакивает.
Вот как это выглядит в коде, смотри:
// 1. Синхронизированный метод. Монитор — это сам объект (this), то есть дверь этого конкретного сортира.
public class SharedCounter {
private int count = 0;
public synchronized void increment() { // Крикнул "ЗАНЯТО!" на весь объект
count++; // Справляй нужду, никто не помешает
}
}
// 2. Синхронизированный блок. Тут мы можем выбрать, на какую конкретно дверь вешать засов.
public class SharedResource {
private final Object lock = new Object(); // Отдельная кабинка, так сказать
private int data;
public void updateData(int value) {
// Тут можно похавать бутерброд, посмотреть в окно — несинхронизированная хуйня
synchronized (lock) { // А вот тут подошёл к своей кабинке 'lock' и щёлкнул засовом
data = value; // Главное дело
} // Выходишь, засов открывается
}
}
А теперь про важные плюшки, которые многие забывают:
-
Реентерабельность (Reentrancy): Это когда ты уже в сортире, а тебе надо взять туалетную бумагу, которая тоже внутри сортира. Так вот, ты её спокойно берёшь, не выходя и не перезащёлкивая дверь. Поток, который уже владеет монитором, может заходить в другие
synchronizedблоки по тому же монитору. Счётчик просто увеличивается. Иначе бы мы все тут повесились на первом же рекурсивном вызове, ёпта. -
wait(), notify(), notifyAll(): А это вообще магия. Допустим, ты зашёл в сортир, а там, блядь, бумаги нет. Так вот,
wait()— это ты сел на унитаз и уснул, отпустив засов (монитор-то освободил!). Ты теперь в wait set (комнате ожидания бумаги). Другой поток (сантехник Вася) может подбросить рулон и крикнутьnotify()— «Эй, там один, бумага есть!». Ты просыпаешься, но тебе ещё надо заново захватить монитор (дождаться, пока сортир свободен и щёлкнуть засовом), чтобы продолжить.notifyAll()— это Вася орёт на весь этаж «БУМАГА ПОДВЕЗЛИ!», просыпаются все, кто ждал.
Короче, монитор в Java — это не просто мьютекс, это такой мьютекс с довеском, который умеет не только не пускать, но и усыплять-будить потоки, когда условия не готовы. Всё гениальное — просто, как три кнопки на унитазе.