Разница между блокировкой и монитором – Java Concurrency

Вы могли столкнуться с этим вопросом на собеседовании, в чем разница между блокировкой и монитором? Что ж, чтобы ответить на этот вопрос, вы должны иметь хорошее представление о том, как работает многопоточность Java под капотом.

Короткий ответ, замки обеспечивают необходимую поддержку для внедрения мониторов. Длинный ответ читайте ниже.

Замки

Блокировка — это тип данных, которые логически являются частью заголовка объекта в динамической памяти. Каждый объект в JVM имеет эту блокировку(или мьютекс), которую любая программа может использовать для координации многопоточного доступа к объекту. Если какой-либо поток хочет получить доступ к переменным экземпляра этого объекта, то поток должен «владеть» блокировкой объекта(установить некоторый флаг в области памяти блокировки). Все остальные потоки, которые пытаются получить доступ к переменным объекта, должны ждать, пока владеющий поток не освободит блокировку объекта(снимет флаг).

Как только поток получает блокировку, он может запросить ту же блокировку снова несколько раз, но затем должен снять блокировку столько же раз, прежде чем она станет доступной для других потоков. Если поток запросит блокировку три раза, например, этот поток продолжит владеть блокировкой, пока он не «снимет» ее три раза.

Обратите внимание, что блокировка приобретается потоком, когда он явно запрашивает ее. В Java это делается с помощью ключевого слова synchronized или с помощью wait и notify.

Мониторы

Монитор — это конструкция синхронизации, которая позволяет потокам иметь как взаимное исключение(используя блокировки), так и сотрудничество, т.е. возможность заставлять потоки ожидать выполнения определенного условия(используя wait-set).

Другими словами, вместе с данными, реализующими блокировку, каждый объект Java логически связан с данными, реализующими набор ожидания. В то время как блокировки помогают потокам работать независимо над общими данными, не мешая друг другу, наборы ожидания помогают потокам сотрудничать друг с другом для совместной работы над общей целью, например, все ожидающие потоки будут перемещены в этот набор ожидания, и все будут уведомлены, как только блокировка будет снята. Этот набор ожидания помогает в построении мониторов с дополнительной помощью блокировки(мьютекса).

Взаимное исключение

Говоря очень простыми словами, монитор похож на здание, содержащее одну специальную комнату(экземпляр объекта), которая может быть занята только одним потоком за раз. Комната обычно содержит некоторые данные, которые необходимо защитить от одновременного доступа. С момента входа потока в эту комнату и до момента его выхода он имеет эксклюзивный доступ к любым данным в комнате. Вход в здание монитора называется «входом в монитор». Вход в специальную комнату внутри здания называется «приобретением монитора». Занятие комнаты называется «владением монитором», а выход из комнаты называется «освобождением монитора». Выход из всего здания называется «выходом из монитора».

Когда поток приходит для доступа к защищенным данным(входа в специальную комнату), он сначала помещается в очередь в здании приема(entry-set). Если никакой другой поток не ждет(владеет монитором), поток получает блокировку и продолжает выполнять защищенный код. Когда поток завершает выполнение, он снимает блокировку и выходит из здания(выходя из монитора).

Если поток прибывает, а другой поток уже владеет монитором, он должен ждать в очереди приема(entry-set). Когда текущий владелец покидает монитор, вновь прибывший поток должен конкурировать с любыми другими потоками, также ожидающими в entry-set. Только один поток победит в соревновании и будет владеть замком.

Функция ожидания не предусмотрена.

Сотрудничество

В целом, взаимное исключение важно только тогда, когда несколько потоков совместно используют данные или какой-либо другой ресурс. Если два потока не работают с какими-либо общими данными или ресурсами, они обычно не могут мешать друг другу и не должны выполняться взаимоисключающим образом. В то время как взаимное исключение помогает потокам не мешать друг другу при совместном использовании данных, сотрудничество помогает потокам работать вместе для достижения некоторой общей цели.

Сотрудничество важно, когда одному потоку нужно, чтобы некоторые данные находились в определенном состоянии, а другой поток отвечает за перевод данных в это состояние, например, проблема производителя/потребителя, когда потоку чтения нужно, чтобы буфер находился в состоянии «непустой», прежде чем он сможет считать какие-либо данные из буфера. Если поток чтения обнаруживает, что буфер пуст, он должен ждать. Поток записи отвечает за заполнение буфера данными. После того, как поток записи выполнил еще некоторую запись, поток чтения может выполнить еще некоторое чтение. Его также иногда называют монитором «Ждать и уведомлять» ИЛИ «Сигнализировать и продолжать», потому что он сохраняет владение монитором и продолжает выполнять область монитора(продолжение) при необходимости. В некоторое время позже уведомляющий поток освобождает монитор, и ожидающий поток восстанавливается, чтобы владеть блокировкой.

Это сотрудничество требует как entry-set, так и wait-set. Ниже приведена диаграмма, которая поможет вам понять это сотрудничество.

java-monitor

На рисунке выше монитор показан в виде трех прямоугольников. В центре большой прямоугольник содержит один поток, владельца монитора. Слева маленький прямоугольник содержит набор записей. Справа еще один маленький прямоугольник содержит набор ожиданий.

Надеюсь, что вышеизложенное обсуждение поможет вам получить больше информации. Вы можете свободно задавать любые вопросы.

Прокрутить вверх