Что такое монитор java
Что такое монитор, упоминаемый в параллельном программировании на Java?
Когда я читаю, что "каждый объект связан с монитором", что это значит?
Это особый объект?
Монитор - это механизм контроля одновременного доступа к объекту.
Это позволяет вам делать:
Это предотвращает одновременный доступ потоков 1 и 2 к контролируемому (синхронизированному) разделу. Один из них запустится, и монитор не позволит другому получить доступ к региону до завершения первого.
Это не особый объект. Это механизм синхронизации, расположенный в корне иерархии классов: java.lang.Object ,
Это также wait а также notify методы, которые также будут использовать монитор объекта для связи между различными потоками.
Монитор - это объект, который обладает как блокировкой, так и набором ожидания. На Яве любой Object может служить монитором.
Для подробного объяснения того, как мониторы работают в Java, я рекомендую прочитать раздел " Механика монитора " в " Параллельное программирование в Java" (предыдущая ссылка отображает предварительный просмотр в книгах Google, и этот раздел доступен для чтения).
- Монитор - это концепция / механизм, который не ограничивается языком Java;
- "В параллельном программировании монитор - это объект или модуль, предназначенный для безопасного использования более чем одним потоком";
- Как знает каждый читатель, каждый объект в Java является подклассом java.lang.Object. Люди java сделали java.lang.Object таким образом, чтобы он имел особенности и характеристики, которые позволяют программистам Java использовать любой объект в качестве монитора. Например, каждый объект имеет очередь ожидания, очередь повторного входа и методы ожидания и уведомления, делающие его монитором;
- Читайте о мониторах здесь.
Язык Java и система времени выполнения поддерживают синхронизацию потоков посредством использования мониторов.
Монитор связан с конкретным элементом данных (переменной условия) и функционирует как блокировка этих данных. Когда поток удерживает монитор для какого-либо элемента данных, другие потоки блокируются и не могут проверять или изменять данные.
Механизм контроля доступа к объектам по одному
Монитор - это конструкция синхронизации, которая позволяет потокам иметь как взаимное исключение, так и возможность ждать (блокировать), чтобы определенное условие стало истинным.
Мониторы также имеют механизм для оповещения других потоков о том, что их условие выполнено. Это сущность, которая обладает как блокировкой, так и набором ожидания. В Java любой объект может служить монитором.
В виртуальной машине Java каждый объект и класс логически связаны с монитором. Чтобы реализовать возможность взаимного исключения мониторов, блокировка (иногда называемая мьютексом) связана с каждым объектом и классом. В терминах операционных систем это называется семафором, мьютекс - это двоичный семафор.
В параллельном программировании нам нужно сосредоточиться на двух вещах.
Когда процесс / поток выполняет свою критическую секцию, никакие другие процессы не могут выполнять свою критическую секцию. (У каждого процесса есть сегмент кода под названием "Критический раздел", в котором осуществляется доступ к общим данным.)
Когда потоки пытаются достичь общей цели путем совместной работы, этим потокам необходимо сотрудничество между ними. Им нужно синхронизироваться, когда они сосредоточены на общей цели.
Мониторы используются для достижения взаимного исключения и синхронизации.
Не путайте эту критическую область с критической секцией, поскольку здесь критическая область упоминается на уровне объекта, а не на уровне потока. Совместно используемые данные считаются критической областью.
Каждый объект и его класс связаны с монитором. Переменные экземпляра объектов, которые необходимо защитить от одновременного доступа, включали критическую область для монитора, которая связана с объектом, и переменные экземпляра классов / статические переменные класса, который необходимо защитить от одновременного доступа, включенные в критическую область для монитор, связанный с классом.
Эта критическая зона защищена замком, который обеспечивает взаимное исключение.
Набор ожидания также связан с монитором, который используется для обеспечения координации между потоками.
Набор записей используется для хранения потоков, которые уже запрошены для блокировки, но блокировка ими еще не установлена.
Как достигается взаимное исключение в Monitor?
Каждый объект связан с монитором, и этот монитор имеет блокировку, при которой каждый поток может блокировать или разблокировать объект, используя эту блокировку, когда он обращается к общим переменным. Явно это означает, что только один поток одновременно может удерживать блокировку монитора. Любые другие потоки, пытающиеся заблокировать эту блокировку, блокируются до тех пор, пока они не смогут получить блокировку.. когда новый поток пытается получить блокировку, и если поток уже владеет блокировкой, этот поток будет ждать записи, установленной для получения блокировки. когда поток, получивший блокировку, завершает свою критическую секцию, он снимает блокировку. Таким образом, следующий поток получит блокировку, но этот следующий поток будет взят из набора записей и будет определяться JVM на основе некоторых критериев, таких как FIFO.
Здесь мы достигли взаимного исключения, поскольку мы предоставляем объекту монопольный доступ к потоку и не позволяем другим потокам входить в их критическую секцию.
Пример кода Java для достижения взаимного исключения с помощью монитора
Как достигается координация / синхронизация через Monitor?
Синхронизация достигается с использованием набора ожидания, который связан с монитором и механизмами "ждать и уведомлять" или "сигнализировать и продолжать". Синхронизация важна, когда одному потоку требуется, чтобы некоторые данные находились в определенном состоянии, а другой поток отвечает за перевод данных в это состояние, например, проблема производителя / потребителя.
Когда поток вызывает метод wait() относительно объекта, он приостанавливается и добавляется к набору ожидания, чтобы дождаться, пока какой-либо другой поток не вызовет notify() или notifyAll() для того же объекта.
Метод notify() используется для пробуждения потоков, находящихся в наборе ожидания монитора конкретного объекта. Есть два способа уведомить ожидающие потоки.
- notify() -> Для всех потоков, ожидающих установки ожидания, метод notify() уведомляет любого из них о произвольном пробуждении. Выбор того, какой именно поток активировать, не является детерминированным и зависит от JVM.
- notifyAll() -> Этот метод просто пробуждает все потоки, ожидающие в наборе ожидания. Пробужденные потоки не смогут продолжить, пока текущий поток не снимет блокировку этого объекта. Пробужденные потоки будут соревноваться обычным образом с любыми другими потоками, которые могут активно конкурировать за синхронизацию.
Пример кода Java для достижения синхронизации с использованием монитора в проблеме производителя-потребителя
Бывают случаи, когда два или более параллельно-выполняемых потока пытаются обратиться к общему ресурсу. Если ресурс может быть изменен в результате выполнения одного из потоков, то другие потоки должны дождаться пока изменения в потоке будут завершены. В противном случае, потоки получат ресурс, данные которого будут ошибочными.
Поток выполнения (который представлен объектом) может завладеть монитором в случае, если он запросил блокировку и монитор свободен на данный момент. После того, как объект вошел в монитор, все остальные объекты-потоки, пытающиеся войти в монитор, приостанавливаются и ожидают до тех пор, пока первый объект не выйдет из монитора.
Монитором может обладать только один поток. Если поток (объект) обладает монитором, то он при необходимости может повторно войти в него.
В языке Java синхронизация применяется к целым методам или фрагментам кода. Исходя из этого существует два способа синхронизации программного кода:
- за счет использования модификатора доступа synchronized ;
- за счет использования оператора synchronized () <> .
2. Модификатор доступа synchronized . Общая форма
Модификатор доступа synchronized применяется при объявлении синхронизированного метода и имеет следующую общую форму:
- MethodName – имя метода, который есть общим ресурсом и его нужно синхронизировать;
- return_type -тип, который возвращает метод;
- parameters – параметры метода.
3. Оператор synchronized() < >. Общая форма
Оператор synchronized() , в отличие от модификатора доступа synchronized , используется для применения синхронизации к объектам (методам), которые изначально при их разработке не предназначались для многопоточного доступа. То есть, в классе не реализованы методы с модификатором доступа synchronized (классы сторонних разработчиков).
Общая форма оператора synchronized () следующая:
- reference – ссылка на синхронизируемый объект;
- фигурные скобки <> , которые определяют блок синхронизации. В этом блоке указываются операторы для синхронизации.
4. Пример, демонстрирующий синхронизированный доступ к общему методу из трех разных потоков. Применение модификатора доступа synchronized
В примере демонстрируется необходимость применения модификатора доступа synchronized с целью упорядочения доступа к ресурсу из разных потоков.
Общим ресурсом является метод Get() класса Array5. Метод Get() возвращает массив из 5 чисел, значения которых последовательно изменяются от 1 к 5. К этому методу будет осуществлена попытка одновременного доступа из разных потоков, поэтому метод обозначен как synchronized .
Инкапсуляция одного потока выполнения осуществляется в классе ArrayThread классическим (стандартным) способом с помощью реализации интерфейса Runnable . Класс ArrayThread содержит следующие общедоступные ( public ) элементы:
В классе Threads представлена функция main() , в которой создается три потока AT1 , AT2 , AT3 типа ArrayThread и один объект A5 . Метод Get() объекта A5 является общим ресурсом для этих трех потоков.
Результат выполнения программы
Если в вышеприведенном примере перед методом Get() класса Array5 убрать ключевое слово synchronized
то последовательного выполнения потоков не будет. В этом случае программа после каждого запуска будет выдавать разный (хаотический) результат, например следующий
5. Пример использования оператора synchronized() <> для синхронизированного доступа к общему ресурсу
Код предыдущего примера (смотрите п. 4), синхронизирующего потоки, можно представить по-другому. В этом случае, вместо модификатора доступа synchronized перед именем метода Get() нужно использовать оператор synchronized () <> . Оператор synchronized должен быть использован в методе run() класса ArrayThread .
Завтра у нас плавненько стартует практически юбилейный поток курс «Разработчик Java» — уже шестой по счёту начиная с апреля прошлого года. А это значит, что мы снова подобрали, перевели интереснейший материал, которым делимся с вами.
Эта памятка поможет Java-разработчикам, работающим с многопоточными программами, понять основные концепции параллелизма и способы их применения. Вы ознакомьтесь с ключевыми аспектами языка Java со ссылками на стандартную библиотеку.
С момента своего создания Java поддерживает ключевые концепции параллелизма, такие как потоки и блокировки. Эта памятка поможет Java-разработчикам, работающим с многопоточными программами, понять основные концепции параллелизма и способы их применения.
Концепция | Описание |
---|---|
Атомарная операция — это операция, которая выполняется полностью или не выполняется совсем, частичное выполнение невозможно. | |
Visibility (видимость) | Условия, при которых один поток видит изменения, сделанные другим потоком |
Таблица 1: Концепции параллелизма
Состояние гонки (Race condition)
Состояние гонки возникает, когда один и тот же ресурс используется несколькими потоками одновременно, и в зависимости от порядка действий каждого потока может быть несколько возможных результатов. Код, приведенный ниже, не является потокобезопасным, и переменная value может быть инициализирована больше, чем один раз, так как check-then-act (проверка на null , а затем инициализация), которая лениво инициализирует поле, не является атомарной:
Гонка данных (Data race)
Гонка данных возникает, когда два или более потока пытаются получить доступ к одной и той же не финальной переменной без синхронизации. Отсутствие синхронизации может привести к внесению изменений, которые не будут видны другим потокам, из-за этого возможно чтение устаревших данных, что, в свою очередь, приводит к бесконечным циклам, поврежденным структурам данных или неточным вычислениям. Этот код может привести к бесконечному циклу, потому что считывающий поток может так и не заметить изменения, внесенные перезаписывающими потоками:
Модель памяти Java: отношение happens-before
Модель памяти Java определяется с точки зрения таких действий, как чтение/запись полей и синхронизация в мониторе. Действия упорядочены с помощью отношения happens-before (выполняется прежде), которое может быть использовано для объяснения того, когда поток видит результат действий другого потока, и что представляет собой правильно синхронизированная программа.
ОТНОШЕНИЯ HAPPENS-BEFORE ИМЕЮТ СЛЕДУЮЩИЕ СВОЙСТВА:
Изображение 1: Пример happens-before
Стандартные функции синхронизации
Ключевое слово synchronized
Ключевое слово synchronized используется для предотвращения одновременного выполнения разными потоками одного и того же блока кода. Оно гарантирует, что, если вы получили блокировку (войдя в синхронизированный блок), данные, на которые наложена эта блокировка, обрабатываются в эксклюзивном режиме, поэтому операция может считаться атомарной. Кроме того, оно гарантирует, что другие потоки увидят результат операции после того, как получат такую же блокировку.
Ключевое слово synchronized можно также раскрыть на уровне методов.
ССЫЛКА, ИСПОЛЬЗУЕМАЯ КАК МОНИТОР | |
---|---|
static | ссылка на объект Class<?> |
non-static | this-ссылка |
Таблица 2: Мониторы, которые используются, когда весь метод синхронизирован
Блокировка реентерабельна (reentrant), поэтому, если поток уже содержит блокировку, он может успешно получить ее снова.
Уровень соперничества влияет на способ захвата монитора:
Описание | |
---|---|
init | Только что создан, пока никем не был захвачен. |
biased | Борьбы нет, и код, защищенный блокировкой, выполняется только одним потоком. Самый дешевый для захвата. |
thin | Монитор захватывается несколькими потоками без борьбы. Для блокировки используется сравнительно дешевый CAS. |
fat | Возникает борьба. JVM запрашивает мьютексы ОС и позволяет планировщику ОС обрабатывать парковки потоков и пробуждения. |
Таблица 3: Состояния мониторов
Методы wait/notify/notifyAll объявляются в классе Object . wait используется, чтобы заставить поток перейти в состояние WAITING или TIMED_WAITING (если передано значение тайм-аута). Чтобы разбудить поток, можно сделать любое из этих действий:
- Имейте в виду, что для того, чтобы использовать wait/notify/notifyAll для объекта, вам необходимо сначала наложить блокировку на этот объект.
- Всегда ждите внутри цикла, проверяющего условие, выполнение которого вы ожидаете. Это касается проблемы синхронизации, если другой поток удовлетворяет условию до начала ожидания. Кроме того, это защищает ваш код от побочных пробуждений, которые могут (и будут) происходить.
- Всегда проверяйте, что вы удовлетворяете условию ожидания перед вызовом notify/notifyAll. Несоблюдение этого требования приведет к уведомлению, но поток не сможет избежать цикла ожидания.
Атомарность
Пакет java.util.concurrent.atomic содержит набор классов, которые поддерживают составные атомарные действия над одним значением без блокировок, подобно volatile .
Используя классы AtomicXXX, можно реализовать атомарную операцию check-then-act :
И AtomicInteger , и AtomicLong имеют атомарную операцию инкремента/декремента:
Если вам нужен счетчик и нет необходимости получать его значение атомарно, подумайте об использовании LongAdder вместо AtomicLong/AtomicInteger . LongAdder обрабатывает значение в нескольких ячейках и увеличивает их число, если нужно, и, следовательно, он работает лучше при высокой конкуренции.
ThreadLocal
Один из способов хранить данные в потоке и сделать блокировку необязательной — это использовать хранилище ThreadLocal . Концептуально ThreadLocal действует так, как будто в каждом потоке есть своя версия переменной. ThreadLocal обычно используется для фиксации значений каждого потока, таких как «текущая транзакция», или других ресурсов. Кроме того, они используются для содержания поточных счетчиков, статистики или генераторов идентификаторов.
Безопасная публикация
Публикация объекта делает его ссылку доступной за пределами текущей области (например, возврат ссылки из геттера). Обеспечение безопасной публикации объекта (только когда он полностью создан) может потребовать синхронизации. Безопасность публикации может быть достигнута с использованием:
- Статических инициализаторов. Только один поток может инициализировать статические переменные, поскольку инициализация класса выполняется под исключительной блокировкой.
- Volatile-поля. Считывающий поток всегда будет считывать последнее значение, потому что запись в volatile-переменную происходит до (happens before) любого последующего чтения.
- Атомарности. Например, AtomicInteger сохраняет значение в volatile-поле, поэтому правило для volatile-переменных здесь тоже применимо.
Убедитесь, что this-ссылка не испарилась во время создания.
Неизменяемые объекты
Одним из самых замечательных свойств неизменяемых объектов является потокобезопасность, поэтому синхронизация для них не нужна. Требования к неизменному объекту:
- Все поля являются final-полями.
- Все поля должны быть либо изменчивыми, либо неизменяемыми объектами, но не выходить за пределы объекта, поэтому состояние объекта не может быть изменено после создания.
- Ссылка this не исчезает во время создания.
- Класс является final-классом, поэтому переопределение его поведения в подклассах невозможно.
Как обрабатывать InterruptedException?
- Очистите все ресурсы и завершите выполнение потока, если это возможно на текущем уровне.
- Объявите, что текущий метод бросает InterruptedException.
- Если метод не порождает исключение InterruptedException, прерванный флаг должен быть восстановлен в true, вызывая Thread.currentThread().interrupt() и должно быть порождено исключение, которое является более подходящим на этом уровне. Очень важно вернуть флаг true, чтобы дать возможность обрабатывать прерывания на более высоком уровне.
В потоках может указываться UncaughtExceptionHandler , который получит уведомление о любом неперехваченном исключении, из-за которого поток прерывается.
Жизнеспособность (Liveness)
Deadlock , или взаимная блокировка, возникает, когда есть несколько потоков и каждый ожидает ресурс, принадлежащий другому потоку, так что формируется цикл из ресурсов и ожидающих их потоков. Наиболее очевидным видом ресурса является монитор объекта, но любой ресурс, который вызывает блокировку (например, wait/notify ), также подходит.
Пример потенциального дэдлока:
Взаимная блокировка происходит, если в одно и то же время:
- Один поток пытается перенести данные с одного аккаунта на другой и уже наложил блокировку на первый аккаунт.
- Другой поток пытается перенести данные со второго аккаунта на первый, и уже наложил блокировку на второй аккаунт.
- Порядок блокировок — всегда накладывайте блокировки в одном и том же порядке.
- Блокировка с тайм-аутом — не блокируйте бессрочно при наложении блокировки, лучше как можно быстрее снимите все блокировки и попробуйте снова.
JVM способен обнаруживать взаимные блокировки мониторов и выводить информацию о них в дампах потоков.
Livelock и потоковое голодание
Livelock возникает, когда потоки тратят все свое время на переговоры о доступе к ресурсу или обнаруживают и избегают тупиковой ситуации так, что поток фактически не продвигается вперед. Голодание возникает, когда потоки сохраняют блокировку в течение длительных периодов, так что некоторые потоки «голодают» без прогресса.
java.util.concurrent
Пулы потоков
Основным интерфейсом для пулов потоков является ExecutorService.java.util.concurrent также предоставляет статическую фабрику Executors, которая содержит фабричные методы для создания пула потоков с наиболее распространенными конфигурациями.
Метод | Описание |
---|---|
newSingleThreadExecutor | Возвращает ExecutorService только с одним потоком. |
newFixedThreadPool | Возвращает ExecutorService с фиксированным количеством потоков. |
newCachedThreadPool | Возвращает ExecutorService с пулом потоков различного размера. |
Возвращает ScheduledExecutorService с одним потоком. | |
newScheduledThreadPool | Возвращает ScheduledExecutorService с основным набором потоков. |
newWorkStealingPool | Возвращает крадущий задачи ExecutorService. |
Таблица 6: Методы статической фабрики
При определении размера пулов потока часто бывает полезно определить размер числа логических ядер в машине, на которой запущено приложение. Получить это значение в Java можно вызвав Runtime.getRuntime().AvailableProcessors() .
Реализация | Описание |
---|---|
ThreadPoolExecutor | Реализация по умолчанию с изменяющим размер пулом потока, одной рабочей очереди и настраиваемой политикой для отклоненных задач (через RejectedExecutionHandler) и создания потоков (через ThreadFactory). |
Расширение ThreadPoolExecutor, которое обеспечивает возможность планирования периодических задач. | |
ForkJoinPool | Крадущий задачи пул: все потоки в пуле пытаются найти и запустить либо поставленные задачи, либо задачи, созданные другими активными задачами. |
Таблица 7: Реализации пула потоков
Описание | |
---|---|
Runnable | Представляет задачу без возвращаемого значения. |
Callable | Представляет вычисление с возвращаемым значением. Он также выбрасывает исходный Exeption, поэтому не требуется обертка для проверенного исключения. |
Таблица 8: Функциональные интерфейсы задач
Future — это абстракция для асинхронного вычисления. Она представляет результат вычисления, который может быть доступен в какой-либо момент: либо вычисленное значение, либо исключение. Большинство методов ExecutorService используют Future как возвращаемый тип. Он предоставляет методы для изучения текущего состояния future или блокирует до тех пор, пока не будет доступен результат.
Пакет java.util.concurrent.locks имеет стандартный интерфейс Lock . Реализация ReentrantLock дублирует функциональность ключевого слова synchronized, но также предоставляет дополнительные функции, такие как получение информации о состоянии блокировки, неблокирующий tryLock() и прерываемая блокировке. Пример использования явного экземпляра ReentrantLock:
ReadWriteLock
Пакет java.util.concurrent.locks также содержит интерфейс ReadWriteLock (и реализацию ReentrantReadWriteLock), который определяется парой блокировок для чтения и записи, обычно позволяя считывать одновременно нескольким читателям, но допуская только одного писателя.
CountDownLatch
CountDownLatch инициализируется счетчиком. Потоки могут вызывать await() , чтобы ждать, пока счетчик не достигнет 0. Другие потоки (или тот же поток) могут вызвать countDown() , чтобы уменьшить счетчик. Нельзя использовать повторно, как только счетчик достигнет 0. Используется для запуска неизвестного набора потоков, как только произошло некоторое количество действий.
CompletableFuture
Параллельные коллекции
Реализация | Описание |
---|---|
Предоставляет семантику копирования при записи, где каждая модификация структуры данных приводит к новой внутренней копии данных (поэтому запись очень дорогая, тогда как чтение дешевое). Итераторы в структуре данных всегда видят снепшот данных с момента создания итератора. |
Таблица 9: Списки в java.util.concurrent
Описание |
---|
Обычно выступает в качестве сегментированной хэш-таблицы. Операции чтения, как правило, не блокируют и отражают результаты последней завершенной записи. Запись первого узла в пустой ящик выполняется просто CAS-ом (сравнить и установить), тогда как другим операциям записи требуются блокировки (первый узел сегмента используется как блокировка). |
Обеспечивает параллельный доступ наряду функциональностью сортированного Map, подобной TreeMap. Границы производительности такие же как у TreeMap, хотя несколько потоков обычно могут читать и записывать из ассоциативного массива без конфликтов, если они не изменяют одну и ту же часть отображения. |
Таблица 10: Ассоциативные массивы в java.util.concurrent
Описание |
---|
Подобно CopyOnWriteArrayList, он использует семантику copy-on-write для реализации интерфейса Set. |
Подобно ConcurrentSkipListMap, но реализует интерфейс Set. |
Таблица 11: Множества в java.util.concurrent
Другим подходом к созданию параллельного множества является обертка параллельного Map:
Очереди выступают в качестве труб между «производителями» и «потребителями». Элементы помещаются в один конец трубы и выходят из другого конца трубы в том же порядке «первый зашел, первый вышел» (FIFO). Интерфейс BlockingQueue расширяет Queue , чтобы предоставить дополнительные варианты того, как обрабатывать сценарий, где очередь может быть заполнена (когда производитель добавляет элемент) или пустой (когда потребитель читает или удаляет элемент). В этих случаях BlockingQueue предоставляет методы, которые либо блокируют навсегда, либо блокируют в течение определенного периода времени, ожидая изменения условия из-за действий другого потока.
Что такое монитор, упомянутый в параллельном программировании на Java?
когда я читаю ,что" каждый объект связан с монитором", что это значит?
Это специальный объект?
монитор-это механизм управления параллельным доступом к объекту.
Это позволяет делать:
это предотвращает одновременный доступ потоков 1 и 2 к контролируемому (синхронизированному) разделу. Один запустится,и монитор предотвратит доступ другого к региону до завершения первого.
это не специальный объект. Это механизм синхронизации помещенный на корень иерархии классов: java.lang.Object .
также wait и notify методы, которые также будут использовать монитор объекта, связей между различными потоками.
монитор-это объект, который обладает обоими замок и a wait значение. В Java, любое Object может служить в качестве монитора.
для подробного объяснения того, как мониторы работают на Java, я рекомендую прочитать Монитор Механики на параллельное программирование на Java (предыдущая ссылка отображает предварительный просмотр в Google книгах, и этот раздел доступен для чтения).
- монитор-это концепция / механизм, который не ограничен языком Java;
- "в параллельном программировании монитор-это объект или модуль, предназначенный для безопасного использования несколькими потоками";
- как знает каждый читатель, каждый объект в Java является подклассом java.ленг.Объект. Люди java сделали java.ленг.Объект таким образом, что он имеет функции и характеристики, которые позволяют программистам Java использовать любой объект в качестве монитора. Например, каждый объект имеет очередь ожидания, очередь повторного входа и ждать и уведомлять методы, делающие его монитором;
- читать про мониторы здесь.
язык Java и система выполнения поддерживают синхронизацию потоков с помощью мониторов.
Монитор связан с определенным элементом данных (переменной условия) и функционирует как блокировка этих данных. Когда поток содержит монитор для какого-либо элемента данных, другие потоки блокируются и не могут проверять или изменять данные.
A для управления доступом к объектам по одному
монитор связан с объектом или элементом данных, который приобретается, когда элемент данных или объект вводится, является блоком синхронизации(критический раздел) и освобождается, когда выход.
Monitor-это конструкция синхронизации, которая позволяет потокам иметь как взаимное исключение, так и возможность ждать (блокировать), пока определенное условие станет истинным.
мониторы также имеют механизм для сигнализации других потоков, что их условие было выполнено. Это сущность, которая обладает как блокировкой, так и набором ожидания. В Java любой объект может служить монитором.
в виртуальной машине Java каждый объект и класс логически связан с монитором. К реализуйте возможность взаимного исключения мониторов, блокировка (иногда называемая мьютексом) связана с каждым объектом и классом. Это называется семафором в терминах операционных систем, мьютекс-двоичный семафор.
Читайте также: