Кто-нибудь может сказать мне преимущество синхронизированного метода перед синхронизированным блоком с примером?
401
Кто-нибудь может сказать мне преимущество синхронизированного метода перед синхронизированным блоком с примером?
Ответы:
Нет явного преимущества использования синхронизированного метода над блоком.
Возможно, единственным (но я бы не назвал это преимуществом) является то, что вам не нужно включать ссылку на объект
this
.Метод:
Блок:
Видеть? Никаких преимуществ вообще.
Блоки действительно имеют преимущество по сравнению с методами , хотя, в основном , в гибкости , потому что вы можете использовать другой объект , как замок в то время как метод синхронизация будет блокировать весь объект.
Для сравнения:
против
Также, если метод растет, вы все равно можете держать синхронизированный раздел отделенным:
источник
synchronized
Блок осуществляется с помощью двух команд,monitorenter
иmonitorexit
, плюс обработчик исключений , который гарантирует , чтоmonitorexit
называется даже в исключительном случае. Это все сохраняется при использованииsynchronized
метода.Единственная реальная разница в том, что синхронизированный блок может выбирать, на каком объекте он синхронизируется. Синхронизированный метод может использовать только
'this'
(или соответствующий экземпляр класса для синхронизированного метода класса). Например, они семантически эквивалентны:Последний является более гибким, поскольку он может конкурировать за связанную блокировку любого объекта, часто переменной-члена. Это также более детально, потому что у вас может быть параллельный код, выполняющийся до и после блока, но все же внутри метода. Конечно, вы могли бы также легко использовать синхронизированный метод путем рефакторинга параллельного кода в отдельные несинхронизированные методы. Используйте то, что делает код более понятным.
источник
Синхронизированный метод
Плюсы:
Минусы:
Синхронизированный блок
Плюсы:
Минусы:
Лично я предпочитаю использовать синхронизированные методы с классами, ориентированными только на то, что требует синхронизации. Такой класс должен быть как можно меньше, и поэтому должно быть легко проверить синхронизацию. Другим не нужно заботиться о синхронизации.
источник
Основное отличие состоит в том, что если вы используете синхронизированный блок, вы можете заблокировать объект, отличный от этого, что позволяет быть более гибким.
Предположим, у вас есть очередь сообщений и несколько производителей и потребителей сообщений. Мы не хотим, чтобы производители вмешивались друг в друга, но потребители должны иметь возможность получать сообщения, не ожидая производителей. Итак, мы просто создаем объект
И теперь каждый раз, когда производители хотят добавить новое сообщение, мы просто фиксируем это:
Таким образом, потребители все еще могут читать, а производители будут заблокированы.
источник
Синхронизированный метод
Синхронизированные методы имеют два эффекта.
Во-первых, когда один поток выполняет синхронизированный метод для объекта, все остальные потоки, которые вызывают синхронизированные методы для того же блока объекта (приостанавливают выполнение), пока первый поток не завершится с объектом.
Во-вторых, при выходе из синхронизированного метода он автоматически устанавливает отношение «до и после» с любым последующим вызовом синхронизированного метода для того же объекта. Это гарантирует, что изменения состояния объекта видны всем потокам.
Обратите внимание, что конструкторы не могут быть синхронизированы - использование ключевого слова synchronized с конструктором является синтаксической ошибкой. Синхронизация конструкторов не имеет смысла, потому что только поток, который создает объект, должен иметь доступ к нему во время его конструирования.
Синхронизированный оператор
В отличие от синхронизированных методов, синхронизированные операторы должны указывать объект, который обеспечивает внутреннюю блокировку: чаще всего я использую это для синхронизации доступа к списку или карте, но я не хочу блокировать доступ ко всем методам объекта.
Q: Внутренние блокировки и синхронизация Синхронизация строится вокруг внутренней сущности, известной как внутренняя блокировка или блокировка монитора. (Спецификация API часто именует эту сущность просто как «монитор».) Внутренние блокировки играют роль в обоих аспектах синхронизации: обеспечение исключительного доступа к состоянию объекта и установление отношений «до и после», которые важны для видимости.
Каждый объект имеет встроенную блокировку, связанную с ним. По соглашению поток, которому требуется исключительный и согласованный доступ к полям объекта, должен получить внутреннюю блокировку объекта перед тем, как получить к ним доступ, а затем снять внутреннюю блокировку, когда это будет сделано с ними. Говорят, что поток владеет внутренней блокировкой между моментом, когда он получил блокировку и снял ее. Пока потоку принадлежит внутренняя блокировка, никакой другой поток не может получить такую же блокировку. Другой поток заблокируется, когда попытается получить блокировку.
Перепроверьте различные выходы с синхронизированным методом, блоком и без синхронизации.
источник
Примечание: статические синхронизированные методы и блоки работают с объектом Class.
источник
Когда компилятор Java преобразует ваш исходный код в байт-код, он обрабатывает синхронизированные методы и синхронизированные блоки совершенно по-разному.
Когда JVM выполняет синхронизированный метод, исполняющий поток идентифицирует, что в структуре method_info метода установлен флаг ACC_SYNCHRONIZED, затем он автоматически получает блокировку объекта, вызывает метод и снимает блокировку. Если возникает исключение, поток автоматически снимает блокировку.
Синхронизация блока метода, с другой стороны, обходит встроенную поддержку JVM для получения блокировки объекта и обработки исключений и требует, чтобы функциональность была явно записана в байтовом коде. Если вы прочитаете байт-код для метода с синхронизированным блоком, вы увидите более десятка дополнительных операций для управления этой функциональностью.
Здесь показаны вызовы для генерации синхронизированного метода и синхронизированного блока:
synchronizedMethodGet()
Метод генерирует следующий байт - код:И вот байт-код из
synchronizedBlockGet()
метода:Одно существенное различие между синхронизированным методом и блоком состоит в том, что синхронизированный блок обычно уменьшает область блокировки. Поскольку объем блокировки обратно пропорционален производительности, всегда лучше блокировать только критическую часть кода. Один из лучших примеров использования синхронизированного блока - это двойная проверка блокировки в шаблоне Singleton, где вместо блокировки целого
getInstance()
метода мы блокируем только критическую часть кода, которая используется для создания экземпляра Singleton. Это резко повышает производительность, потому что блокировка требуется только один или два раза.При использовании синхронизированных методов вам нужно будет проявлять особую осторожность, если вы смешиваете статические синхронизированные и нестатические синхронизированные методы.
источник
monitorenter
иmonitorexit
перед запуском кода.Чаще всего я использую это для синхронизации доступа к списку или карте, но я не хочу блокировать доступ ко всем методам объекта.
В следующем коде один поток, модифицирующий список, не будет блокировать ожидание потока, который модифицирует карту. Если бы методы были синхронизированы на объекте, то каждый метод должен был бы ждать, даже если изменения, которые они делают, не будут конфликтовать.
источник
С синхронизированными блоками у вас может быть несколько синхронизаторов, так что одновременно может происходить несколько одновременных, но не конфликтующих вещей.
источник
Синхронизированные методы можно проверить с помощью API отражения. Это может быть полезно для тестирования некоторых контрактов, например, все методы в модели синхронизированы .
Следующий фрагмент выводит все синхронизированные методы Hashtable:
источник
Важное замечание по использованию синхронизированного блока: осторожно, что вы используете в качестве объекта блокировки!
Фрагмент кода из user2277816 выше иллюстрирует этот момент в том смысле, что ссылка на строковый литерал используется в качестве объекта блокировки. Поймите, что строковые литералы автоматически внедряются в Java, и вы должны начать видеть проблему: каждый фрагмент кода, который синхронизируется с литералом «блокировка», разделяет одну и ту же блокировку! Это может легко привести к взаимоблокировке с совершенно не связанными частями кода.
С объектами нужно быть осторожнее. Примитивы в штучной упаковке также представляют опасность, поскольку методы autoboxing и valueOf могут повторно использовать одни и те же объекты в зависимости от значения.
Для получения дополнительной информации см .: https://www.securecoding.cert.org/confluence/display/java/LCK01-J.+Do+not+synchronize+on+objects+that+may+be+reused
источник
Часто использование блокировки на уровне метода слишком грубо. Зачем блокировать кусок кода, который не имеет доступа к каким-либо общим ресурсам, блокируя весь метод. Поскольку каждый объект имеет блокировку, вы можете создавать фиктивные объекты для реализации синхронизации на уровне блоков. Уровень блока более эффективен, потому что он не блокирует весь метод.
Вот пример
Уровень метода
Уровень блока
[Редактировать]
Для
Collection
какVector
иHashtable
они синхронизированы , когдаArrayList
илиHashMap
нет , и вы должны набора синхронизированы ключевым слово или запускайте Collections синхронизированного метода:источник
Единственное отличие: синхронизированные блоки допускают гранулярную блокировку в отличие от синхронизированного метода
В основном
synchronized
блок или методы использовались для написания поточно-безопасного кода, избегая ошибок несогласованности памяти.Этот вопрос очень старый и многое изменилось за последние 7 лет. Новые конструкции программирования были введены для обеспечения безопасности потоков.
Вы можете достичь безопасности потоков, используя расширенный API параллелизма вместо
synchronied
блоков. На этой странице документации представлены хорошие программные конструкции для обеспечения безопасности потоков.Объекты блокировки поддерживают идиомы блокировки, которые упрощают многие параллельные приложения.
Исполнители определяют высокоуровневый API для запуска и управления потоками. Реализации исполнителя, предоставляемые java.util.concurrent, обеспечивают управление пулом потоков, подходящее для крупномасштабных приложений.
Параллельные сборы упрощают управление большими коллекциями данных и могут значительно сократить потребность в синхронизации.
Атомарные переменные имеют функции, которые минимизируют синхронизацию и помогают избежать ошибок согласованности памяти.
ThreadLocalRandom (в JDK 7) обеспечивает эффективную генерацию псевдослучайных чисел из нескольких потоков.
Лучшая замена синхронизированным - ReentrantLock , который использует
Lock
APIПример с замками:
См. Также пакеты java.util.concurrent и java.util.concurrent.atomic для других программных конструкций.
См. Также этот связанный вопрос:
Синхронизация против блокировки
источник
Синхронизированный метод используется для блокировки всех объектов Синхронизированный блок используется для блокировки определенного объекта
источник
В общем, это в основном то же самое, кроме того, что они явно относятся к монитору объекта, который используется против неявного объекта this. Недостатком синхронизированных методов, который, я думаю, иногда упускают из виду, является то, что при использовании ссылки this для синхронизации вы оставляете открытой возможность блокировки внешних объектов на одном и том же объекте. Это может быть очень тонкая ошибка, если вы столкнетесь с ней. Синхронизация по внутреннему явному объекту или другому существующему полю может избежать этой проблемы, полностью инкапсулируя синхронизацию.
источник
Как уже было сказано, синхронизированный блок может использовать пользовательскую переменную в качестве объекта блокировки, когда синхронизированная функция использует только «this». И, конечно, вы можете манипулировать областями своей функции, которые должны быть синхронизированы. Но все говорят, что нет никакой разницы между синхронизированной функцией и блоком, который покрывает всю функцию, используя «this» в качестве объекта блокировки. Это не так, разница в байт-коде, который будет сгенерирован в обеих ситуациях. В случае использования синхронизированного блока должна быть выделена локальная переменная, которая содержит ссылку на «это». И как результат, у нас будет немного больший размер для функции (не имеет значения, если у вас всего несколько функций).
Более подробное объяснение разницы вы можете найти здесь: http://www.artima.com/insidejvm/ed2/threadsynchP.html
источник
В случае синхронизированных методов, блокировка будет получена на объекте. Но если вы используете синхронизированный блок, у вас есть возможность указать объект, для которого будет получена блокировка.
Пример :
источник
Я знаю, что это старый вопрос, но, прочитав ответы здесь, я не заметил, чтобы кто-то упомянул, что иногда
synchronized
метод может быть неправильной блокировкой.Из Java-параллелизма на практике (стр. 72):
Приведенный выше код выглядит как поточно-ориентированный. Однако на самом деле это не так. В этом случае блокировка получается на экземпляре класса. Однако возможно изменение списка другим потоком, не использующим этот метод. Правильный подход будет использовать
Приведенный выше код блокирует все потоки, пытающиеся изменить список, от изменения списка до завершения синхронизированного блока.
источник
List
может привести к проблемам с производительностью, если существует журнал кода, который не обязательно должен быть синхронизированНа практике преимущество синхронизированных методов перед синхронизированными блоками заключается в том, что они более устойчивы к идиотам; поскольку вы не можете выбрать произвольный объект для блокировки, вы не можете неправильно использовать синтаксис синхронизированного метода, чтобы делать глупые вещи, такие как блокировка строкового литерала или блокировка содержимого изменяемого поля, которое изменяется из-под потоков.
С другой стороны, с синхронизированными методами вы не можете защитить блокировку от получения любым потоком, который может получить ссылку на объект.
Таким образом, использование синхронизированного в качестве модификатора в методах лучше для защиты ваших сотрудников-коров от вреда для себя, в то время как использование синхронизированных блоков в сочетании с частными объектами окончательной блокировки лучше для защиты вашего собственного кода от сотрудников-коров.
источник
Из резюме спецификации Java: http://www.cs.cornell.edu/andru/javaspec/17.doc.html
Основываясь на этих описаниях, я бы сказал, что большинство предыдущих ответов верны, и синхронизированный метод может быть особенно полезен для статических методов, где в противном случае вам пришлось бы выяснить, как получить объект «Class», представляющий класс, в котором этот метод был определены «.
Изменить: я первоначально думал, что это были цитаты из фактической спецификации Java. Уточнил, что эта страница является лишь кратким описанием / объяснением спецификации
источник
TLDR; Ни используйте
synchronized
модификатор, ниsynchronized(this){...}
выражение, ноsynchronized(myLock){...}
гдеmyLock
находится конечное поле экземпляра, содержащее закрытый объект.Разница между использованием
synchronized
модификатора в объявлении метода иsynchronized(..){ }
выражением в теле метода заключается в следующем:synchronized
Модификатор указанный на подписи методыsynchronized(this) { .... }
, иthis
объект в качестве блокировки при объявлении нестатического метода или включающего класса при объявлении статического метода.synchronized(...){...}
Выражение позволяетОднако использование
synchronized
модификатора илиsynchronized(...) {...}
с использованиемthis
в качестве объекта блокировки (как вsynchronized(this) {...}
) имеет тот же недостаток. Оба используют свой собственный экземпляр в качестве объекта блокировки для синхронизации. Это опасно, потому что не только сам объект, но и любой другой внешний объект / код, который содержит ссылку на этот объект, также может использовать его в качестве блокировки синхронизации с потенциально серьезными побочными эффектами (снижение производительности и взаимоблокировки ).Поэтому рекомендуется не использовать ни
synchronized
модификатор, ниsynchronized(...)
выражение в сочетании сthis
объектом блокировки, а с объектом блокировки, закрытым для этого объекта. Например:Вы также можете использовать несколько объектов блокировки, но необходимо соблюдать особую осторожность, чтобы гарантировать, что это не приведет к взаимным блокировкам при использовании вложенных.
источник
Я предполагаю, что этот вопрос о разнице между Thread Safe Singleton и Lazy инициализацией с двойной проверкой блокировки . Я всегда ссылаюсь на эту статью, когда мне нужно реализовать какой-то конкретный синглтон.
Ну, это потокобезопасный синглтон :
Это Ленивая инициализация с двойной проверкой блокировки :
Пожалуйста, обратитесь к этой статье для более подробной информации:
https://www.geeksforgeeks.org/java-singleton-design-pattern-practices-examples/
источник
Синхронизация с потоками. 1) НИКОГДА не используйте синхронизированный (это) в потоке, он не работает. Синхронизация с (this) использует текущий поток в качестве объекта блокировки потока. Поскольку каждый поток не зависит от других потоков, координация синхронизации отсутствует. 2) Тесты кода показывают, что в Java 1.6 на Mac не работает синхронизация методов. 3) synchronized (lockObj), где lockObj - это общий общий объект всех синхронизирующихся на нем потоков. 4) ReenterantLock.lock () и .unlock () работают. Смотрите Java уроки для этого.
Следующий код показывает эти пункты. Он также содержит потокобезопасный вектор, который будет заменен на ArrayList, чтобы показать, что многие потоки, добавляемые в вектор, не теряют никакой информации, в то время как тот же самый с ArrayList может потерять информацию. 0) Текущий код показывает потерю информации из-за состояния гонки. A) Прокомментируйте текущую помеченную строку A и раскомментируйте строку A над ней, затем запустите, метод теряет данные, но это не должно. B) Обратный шаг A, раскомментируйте B и // конец блока}. Затем запустите, чтобы увидеть результаты без потери данных. C) Закомментируйте B, раскомментируйте C. Выполните, посмотрите, как синхронизируется (это) потеря данных, как и ожидалось. Не успеваю завершить все варианты, надеюсь, это поможет. Если выполняется синхронизация по (этому) или метод синхронизации работает, укажите, какую версию Java и ОС вы тестировали. Спасибо.
источник