Почему синхронизация стоит дорого в Java?
Я действительно Новичок в Java, и я читал, что "синхронизировано" "очень дорого" на Java. Все, что я хочу знать, это что дорого и как это дорого? Спасибо.
5 ответов
может быть, это не так плохо, как вам кажется!--2-->
раньше это было ужасно (возможно, поэтому вы читали, что это было "очень дорого"). Эти мемы могут долго вымирать
здесь хорошая статья об этом
сколько стоит синхронизация?
из-за правил, связанных с очисткой кэша и недействительностью, синхронизированный блок на языке Java обычно дороже, чем объекты критического раздела предложенные много платформ, которые обычно снабжены атомной инструкцией машины "бита теста и набора". Даже если программа содержит только один поток, работающий на одном процессоре, вызов синхронизированного метода все еще медленнее, чем вызов несинхронизированного метода. Если синхронизация действительно требует борьбы за блокировку, штраф за производительность значительно больше, так как потребуется несколько переключателей потоков и системных вызовов.
к счастью, непрерывные улучшения в JVM улучшили общую производительность программы Java и уменьшили относительную стоимость синхронизации с каждым выпуском, и будущие улучшения ожидаются. Кроме того, затраты на производительность синхронизации часто завышены. Один известный источник привел, что синхронизированный вызов метода в 50 раз медленнее, чем несинхронизированный вызов метода. Хотя это утверждение может быть истинным, оно также вводит в заблуждение и привело к многие разработчики избегают синхронизации даже в тех случаях, когда это необходимо.
сказав, что - параллельное программирование все еще может быть медленным, но не так много из этого-чисто вина Java сейчас. Существует компромисс между тонкой и грубой замок. Слишком грубый очевидно плох, но возможно быть слишком точен слишком, по мере того как замки имеют ненулевую цену.
важно рассмотреть конкретный ресурс в разделе "раздор". Механические жесткие диски являются примером, где больше потоки могут привести к хуже производительность.
Это дорого, потому что если вы используете потоки, и несколько потоков должны пройти через синхронизированный раздел кода, только один из них может быть выполнен одновременно.
Это как узкое место.
Это даже дорого, когда вы используете один поток, потому что он все равно должен проверить, разрешено ли ему работать.
Если вы уменьшите использование синхронизированных сегментов, вашему потоку не придется останавливаться, чтобы увидеть, могут ли они работать ( конечно, им не нужно обмен данными)
высокоуровневый обзор того, как работает синхронизация может быть найден здесь
http://img20.imageshack.us/img20/2066/monitor28synchronizatioc.png
монитор стиля Java
этой статьи в IBM на самом деле очень хорошо суммирует основные моменты синхронизации.
из-за правил, связанных с промывкой кэша и недействительностью, синхронизированный блок на языке Java, как правило, дороже, чем средства критического раздела, предлагаемые многими платформами, которые обычно реализуются с помощью атомной "тестовой и заданной битной" машинной инструкции. Даже если программа содержит только один поток выполняется на одиночный процессор, синхронизированный вызов метода все еще медленнее, чем несинхронизированный вызов метода. Если синхронизация действительно требует борьбы за блокировку, штраф за производительность значительно больше, так как потребуется несколько переключателей потоков и системных вызовов.
Это не так специфично для Java. Синхронизация может считаться "дорогой" в любой многопоточной среде, если не выполняется правильно. Особенно ли это плохо на Java, я не знаю.
Это предотвращает одновременный запуск потоков, если они используют один и тот же ресурс. Но, поскольку они do использовать один и тот же ресурс, нет лучшего варианта (это должно быть сделано).
проблема в том, что люди часто защищают ресурс с слишком большой объем. Для например, плохо разработанная программа может синхронизировать весь массив объектов, а не каждый отдельный элемент массива (или даже часть массива).
Это означало бы, что поток, пытающийся прочитать элемент 7, должен ждать чтения или записи элемента 22 потока. Не нужный. Если бы степень детализации синхронизации была на уровне элемента, а не на уровне массива, эти два потока не мешали бы друг другу.
только когда два потока пытались доступ к то же самое элемент будет ли конфликт ресурсов. Вот почему общее правило состоит в том, чтобы защитить как можно меньший ресурс (при условии ограничений на количество синхронизаций, конечно).
но, честно говоря, не имеет значения, насколько это дорого, если альтернативой является повреждение данных из-за двух потоков, борющихся за один ресурс. Напишите приложение правильно и только беспокоиться о проблемах производительности, если и когда они появляются ("получить его работа первая затем заставить его работать быстро" - моя любимая мантра).
другие ответы дают хороший уровень технических деталей, которые я не буду пытаться повторить.
что я сделаю, так это посоветую вам проверить даты статей (а также подразумеваемую компетентность и осведомленность автора). Синхронизации в Java был очень медленно в более ранних JVMs. Тем не менее, в последнее время он значительно улучшился, так что незапланированная синхронизация намного быстрее, чем вы думаете, и незапланированная синхронизация улучшилась тоже.
имейте в виду, этот вопрос, возможно, не имеет значения - если вам нужно синхронизировать, чтобы обеспечить правильность, вы нужно для синхронизации для обеспечения корректности. Единственный раз, когда я вижу, что скорость является проблемой, - это если вы рассматриваете возможность создания безблокировочной реализации (используя очень эффективный, но сложный java.утиль.параллельный.замки.AbstractQueuedSynchronizer), или, возможно, рассмотреть возможность использования другого языка для вашей задачи вместо.
В общем, я думаю, что лучший вывод заключается в том, что синхронизация, как правило, достаточно быстра для использования на первой итерации. Как и во всех случаях с производительностью, сначала код для ясности и правильности, а затем только оптимизировать то, что вы измеряете, чтобы быть дорогостоящей частью вашего приложения. Как правило, это не будет стоить синхронизации*.