В чем разница между синхронизацией на lockObject и использованием этого как блокировки?

Я знаю разницу между синхронизированным методом и синхронизированным блоком, но я не уверен в синхронизации части блока.

Предполагая, что у меня есть этот код

class Test { private int x=0; private Object lockObject = new Object(); public void incBlock() { synchronized(lockObject) { x++; } System.out.println("x="+x); } public void incThis() { // same as synchronized method synchronized(this) { x++; } System.out.println("x="+x); } } 

В этом случае в чем разница между использованием lockObject и использованием этого как блокировки? Мне кажется, что то же самое.

Когда вы решите использовать синхронизированный блок, как вы решаете, какой из объектов является блокировкой?

Лично я почти никогда не блокирую «это». Обычно я блокирую конфиденциальную ссылку, которую знаю, что никакой другой код не будет заблокирован. Если вы заблокируете «это», тогда любой другой код, который знает о вашем объекте, может захотеть заблокировать его. Хотя это вряд ли произойдет, это, безусловно, может сделать – и может вызвать взаимоблокировки или просто чрезмерную блокировку.

Нет ничего особенного в том, что вы запираете – вы можете думать об этом как о знаке, эффективно. Любая блокировка с тем же токеном будет пытаться получить тот же замок. Если вы не хотите, чтобы другой код мог получить один и тот же замок, используйте приватную переменную. Я также рекомендую вам сделать переменную final – я не могу вспомнить ситуацию, когда я когда- либо хотел изменить переменную блокировки на протяжении всего жизненного цикла объекта.

У меня был такой же вопрос, когда я читал Java Concurrency In Practice, и я подумал, что добавлю дополнительную точку зрения на ответы, предоставленные Jon Skeet и spullara.

Вот пример кода, который блокирует даже «быстрые» setValue(int) / getValue() то время как метод doStuff(ValueHolder) выполняется.

 public class ValueHolder { private int value = 0; public synchronized void setValue(int v) { // Or could use a sychronized(this) block... this.value = 0; } public synchronized int getValue() { return this.value; } } public class MaliciousClass { public void doStuff(ValueHolder holder) { synchronized(holder) { // Do something "expensive" so setter/getter calls are blocked } } } 

Недостатком использования this для синхронизации является то, что другие classы могут синхронизироваться по ссылке на ваш class (не через this , конечно). Вредоносная или непреднамеренное использование synchronized ключевого слова при блокировке ссылки на объект может привести к тому, что ваш class будет плохо себя вести при параллельном использовании, поскольку внешний class может эффективно блокировать ваши -синхронизированные методы, и вы ничего не можете сделать (в своем classе), чтобы запретить это во время выполнения. Чтобы избежать этой потенциальной ловушки, вы синхронизировались на private final Object или использовали интерфейс Lock в java.util.concurrent.locks .

Для этого простого примера вы можете поочередно использовать AtomicInteger а не синхронизировать setter / getter.

Пункт 67 Эффективного Java Second Edition – Избегайте чрезмерной синхронизации, поэтому я бы синхронизировал на закрытом объекте блокировки.

Каждый объект Java может выступать в качестве монитора. Выбор одного зависит от того, какую гранулярность вы хотите. Выбор «этого» имеет преимущество и недостаток, что другие classы также могут синхронизироваться на одном мониторе. Мой совет заключается в том, чтобы избежать использования ключевого слова synchronize напрямую и вместо этого использовать конструкции из библиотеки java.util.concurrency, которые являются более высоким уровнем и имеют четко определенную семантику. У этой книги есть много замечательных советов в ней от очень известных экспертов:

Практическое применение Java-параллелизма http://amzn.com/0321349601

В этом случае не имеет значения, какой объект вы выберете для блокировки. Но вы должны последовательно использовать один и тот же объект для блокировки для достижения правильной синхронизации. Выше код не обеспечивает правильную синхронизацию, поскольку вы когда-то использовали этот «этот» объект как блокировку, а затем «lockObject» как блокировку.

Interesting Posts

Есть ли способ выполнить установку osx с флеш-накопителя?

Не удалось открыть Android 6.0: EACCES (Permission denied)

Почему сервер передач-job-server не принимает соединения при работе в качестве службы?

Удалить шаблон по умолчанию в Microsoft Excel 2010

Можно ли использовать std :: basic_string в качестве непрерывного буфера при таргетинге на C ++ 03?

Windows 10 «Некоторые настройки управляются вашей организацией» (gpedit.msc не работает)

Эффективный способ делать массовую вставку / обновление с помощью Entity Framework

Java 8 U40 TextFormatter (JavaFX) для ограничения ввода пользователя только для десятичного числа

если два слова являются анаграммами друг друга

Ошибка AdMob с помощью : непризнанный селектор

Приложения Windows 8 Metro не загружаются

Разница между типичным типом и подстановочным типом

Как конвертировать Reader в InputStream и Writer в OutputStream?

Могу ли я автоматически генерировать субтитры из видеофайла?

Почему sizeof (param_array) – размер указателя?

Давайте будем гением компьютера.