Насколько тяжелы Java-мониторы?

Скажем, у меня есть массив из тысяч объектов и небольшое количество потоков, которые могут обращаться к каждому из объектов. Я хочу защитить доступ к одному из методов объектов. Самый простой способ - объявить этот метод как synchronized. Однако это может привести к созданию тысяч мониторов, в зависимости от того, каким образом они будут реализованы. Если бы это был Win32, я бы никогда не создал тысячи объектов ядра, таких как Mutex, но CRITICAL_SECTION могли быть правдоподобными. Мне интересно, что происходит на Java. Учитывая, что вероятность конкуренции низкая, будет ли использование мониторов налагать больше, чем простое количество памяти, которое им требуется? Насколько распространена практика использования такой синхронизации с низкой степенью детализации в Java?

(Есть очевидные обходные пути, такие как использование гораздо меньшего массива объектов синхронизации, к которым будет обращаться с помощью некоторого хэша. Я не ищу практического решения, я ищу прозрение).

Ответ 1

Вы уже заплатили (в большинстве случаев, и с низким уровнем конкуренции) штраф за то, что мониторы вокруг с помощью Java... нет смысла не использовать их. В частности, в случае с низким уровнем конкуренции они очень дешевы (см. пункты 2.1, 2.2, 2.3 здесь и Пункт № 1 здесь), и JVM может полностью оптимизировать их для нескольких случаев. Если вы используете временный монитор только временно, JVM сделает его "достаточно большим" (это означает, что он начинается как перевертывание битов, может расширяться для простых случаев конкуренции выделенному стекю атомным флагом, а при постоянном конфликте есть объект-монитор, выделенный для это, все они будут разворачиваться обратно в низкую служебную ситуацию, поскольку конкуренция уменьшится) и вернуть пространство позже. В той мере, в какой блокировка на этих объектах является "правильной вещью" на стороне приложения, я бы сказал, для этого.

Однако здесь есть запах дизайна. Блокировка на так много объектов не звучит здорово. Кроме того, если у вас есть какие-либо последовательные условия блокировки, вы не сможете рассуждать о возможных взаимоблокировках. Я предлагаю вам увеличить свой вопрос с более подробной информацией о приложении, и мы можем спросить, является ли блокировка на большом пуле объектов правой строкой.

Эта презентация Dave Dice дает некоторое полезное представление о том, как работает синхронизация Java6, и эта запись является сокровищницей информации о синхронизации на Java. Если вы действительно, действительно заботитесь о том, как "большая" полнофункциональная структура objectmonitor (вступает в игру в рассматриваемом случае), здесь здесь > . На странице вики-страницы внутренних служб HotSpot также содержится подробная подробная информация.

Ответ 2

Мьютексы Java достаточно дешевы, чтобы вы могли иметь сотни тысяч синхронизированных объектов и не замечали этого.

В незащищенном случае Java-мьютекс состоит из всего 2 бит в слове флагов. JVM связывает объект блокировки большой тяжести с мьютексом Java при рассмотрении мьютекса, а затем освобождает блокировку ОС, когда мьютекс был выведен всеми потоками.

Обзор того, как реализованы мьютексы Java, можно найти в слайдах с 9 по 23 из эту презентацию из Javaone 2006.


Обратите внимание, что реализация и производительность мьютексов зависит от поставщика/выпуска Java, который вы используете, и от платформы, на которой вы работаете.

  • В ранних версиях Java мьютексы были значительно дороже.
  • Возможно, успехи были достигнуты после публикации статьи JavaOne 2006... опубликованной или нет.

Ответ 3

Я думаю, что Collections.synchronizedCollection позволяет одному потоку обращаться к коллекции. Однако проблема создания мониторов существует.