Насколько тяжелы Java-мониторы?
Скажем, у меня есть массив из тысяч объектов и небольшое количество потоков, которые могут получить доступ к каждому из объектов. Я хочу защитить доступ к одному из методов объектов. Проще всего было бы объявить этот метод как synchronized
, Однако это может привести к созданию тысяч мониторов, в зависимости от того, как они реализованы. Если бы это был Win32, я бы никогда не создал тысячи объектов ядра, таких как Mutex, но CRITICAL_SECTIONs могли бы быть правдоподобными. Мне интересно, что происходит в Java. Учитывая низкую вероятность возникновения конфликтов, будет ли использование мониторов накладывать больше, чем просто объем памяти, который им требуется? Насколько распространена практика использования синхронизации с такой низкой степенью детализации в Java?
(Очевидно, что есть обходные пути, такие как использование гораздо меньшего массива объектов синхронизации, доступ к которому можно получить с помощью некоторого хэша. Я не ищу практического решения, я ищу понимание).
3 ответа
Вы уже заплатили (в большинстве случаев и с низким уровнем конкуренции) штраф за использование мониторов с помощью Java... нет смысла их не использовать. В частности, в случае с низким уровнем конкуренции они очень дешевы (см. Пункты 2.1, 2.2, 2.3 здесь и пункт № 1 здесь), и JVM может полностью их оптимизировать для ряда случаев. Если вы используете монитор объекта только временно, JVM сделает его "достаточно большим" (что означает, что он начинается с переворачивания битов, может расшириться для простых случаев конфликта до атомарного флага, выделенного стеком, и при постоянном конфликте иметь объектный монитор, выделенный для это; все они будут развернуты обратно в дело с низкими накладными расходами, поскольку спор уменьшится), и освободят место позже. В той степени, в которой блокировка этих объектов является "правильной вещью" на стороне приложения, я бы сказал, пойти на это.
Тем не менее, здесь есть дизайнерский запах. Блокировка на многих объектах не звучит здорово. Кроме того, если у вас есть какие-либо условия последовательной блокировки, вы не сможете рассуждать о возможных тупиках. Я предлагаю вам дополнить свой вопрос более подробной информацией о приложении, и мы можем спросить, является ли блокировка большого пула объектов правильным решением.
Эта презентация Дэйва Дайса дает некоторое полезное представление о том, как работает синхронизация Java6, и эта запись в блоге является сокровищницей информации о синхронизации на Java. Если вы действительно, действительно заботитесь о том, как "большой" полный на структуре objectmonitor это (вступает в игру в утверждало случае), то код здесь. На вики-странице HotSpot также есть много полезной информации.
Java-мьютексы достаточно дешевы, так что вы можете иметь сотни тысяч синхронизированных объектов и не замечать этого.
В неконтролируемом случае мьютекс Java состоит всего из 2 битов в слове флагов. JVM связывает только тяжелый объект блокировки ОС с мьютексом Java, когда мьютекс утверждается, и затем снимает блокировку ОС, когда мьютекс был завершен всеми потоками.
Обзор того, как реализованы мьютексы Java, можно найти на слайдах 9–23 этой презентации от Javaone 2006.
Обратите внимание, что реализация и производительность мьютексов могут зависеть от поставщика / выпуска Java, который вы используете, и платформы, на которой вы работаете.
- В ранних выпусках Java мьютексы были значительно дороже.
- Вполне возможно, что были достигнуты успехи со времени выхода статьи о JavaOne 2006... опубликовано или нет.
Я думаю, что Collections.synchronizedCollection позволил одному потоку получить доступ к коллекции. Однако проблема создания мониторов существует.