Почему синхронизация стоит дорого на Java?

Я действительно новичок в Java, и я прочитал, что synchronized является "очень дорогим" в Java. Все, что я хочу знать, это то, что дорого и как это дорого?

Благодарю.

Ответ 1

Может быть, это не так плохо, как вы думаете

Раньше это было ужасно (возможно, поэтому вы читали, что это было "очень дорого"). Эти мемы могут долго вымирать

Сколько стоит синхронизация?

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

К счастью, постоянные улучшения в JVM улучшили общую производительность Java-программ и снизили относительную стоимость синхронизации с каждым выпуском, и ожидаются будущие улучшения. Кроме того, затраты на синхронизацию часто завышены. Один известный источник цитирует, что синхронизированный вызов метода в 50 раз медленнее, чем несинхронизированный вызов метода. Хотя это утверждение может быть правдой, оно также вводит в заблуждение и заставляет многих разработчиков избегать синхронизации даже в тех случаях, когда это необходимо.

Сказав это, параллельное программирование все еще может быть медленным, но не так много, это теперь просто ошибка Java. Существует компромисс между тонкой и грубой блокировкой. Слишком грубый, очевидно, плохо, но возможно и слишком хорошо, так как замки имеют ненулевую стоимость.

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

Ответ 2

Это дорого, потому что, если вы используете потоки, а несколько потоков должны проходить через синхронизированный раздел кода, только один из них может выполняться одновременно.

Это как узкое место.

Это даже дорого, когда вы используете один поток, потому что он должен проверять в любом случае, если ему разрешено работать.

Если вы уменьшите использование синхронизированных сегментов, вашему потоку не придется останавливаться, чтобы увидеть, могут ли они выполняться (конечно, им не нужно обмениваться данными)

Подробный обзор того, как работает синхронизация, можно найти здесь

http://img20.imageshack.us/img20/2066/monitor28synchronizatioc.png

Монитор стиля Java

Ответ 3

Это не относится к Java. Синхронизация может считаться "дорогой" в любой многопоточной среде, если она выполнена неправильно. Является ли это особенно плохо на Java, я не знаю.

Он предотвращает одновременную работу потоков, если они используют один и тот же ресурс. Но, поскольку они используют один и тот же ресурс, нет лучшего варианта (это нужно сделать).

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

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

Только когда два потока попытались получить доступ к одному и тому же элементу, будет существовать конфликт ресурсов. Вот почему общее правило состоит в том, чтобы защитить только как можно меньший ресурс (с учетом ограничений на количество синхронизаций, конечно).

Но, честно говоря, неважно, насколько это дорого, если альтернативой является повреждение данных из-за двух потоков, сражающихся за один ресурс. Правильно пишите свое приложение и беспокоитесь только о проблемах с производительностью, если и когда они появятся ( "Сначала запустите его, а затем быстро заработайте" ) - это моя любимая мантра.

Ответ 4

Эта статья в IBM фактически очень хорошо описывает основные моменты синхронизации.

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

Ответ 5

Другие ответы дают хороший технический уровень, который я не собираюсь повторять.

Что я буду делать, советуем вам проверять даты статей (а также подразумеваемая компетентность и осведомленность автора). Синхронизация в Java была очень медленной в предыдущих JVM. Тем не менее, в последнее время он значительно улучшился, так что неуправляемая синхронизация намного быстрее, чем вы могли бы подумать, а также улучшилась неконтрастная синхронизация.

Помните, что этот вопрос, возможно, не имеет значения - если вам нужно синхронизировать, чтобы обеспечить правильность, вам нужно синхронизировать, чтобы обеспечить правильность. Единственный раз, когда я могу видеть, что скорость является проблемой, - если вы решили вместо этого создать незаблокированную реализацию (используя очень эффективный, но сложный java.util.concurrent. locks.AbstractQueuedSynchronizer), или, возможно, вместо использования другого языка для вашей задачи.

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