У меня возник тот же вопрос, когда я читал «Параллелизм на практике на Java», и я подумал, что хотел бы добавить дополнительную точку зрения на ответы, представленные Джоном Скитом и Спулларой.
Вот пример кода, который блокирует даже «быстрые» методы 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
для синхронизации является то, что другие классы могут синхронизироваться по ссылке на ваш класс (конечно, не через this
). Злонамеренное или непреднамеренное использование ключевого слова synchronized
при блокировке ссылки на ваш объект может привести к тому, что ваш класс будет плохо вести себя при одновременном использовании, поскольку внешний класс может эффективно блокировать ваши this
-синхронизированные методы, и вы ничего не можете сделать (в ваш класс), чтобы запретить это во время выполнения. Чтобы избежать этой потенциальной ловушки, вы должны синхронизироваться на private final Object
или использовать интерфейс Lock
в java.util.concurrent.locks
.
В этом простом примере вы можете поочередно использовать AtomicInteger
вместо синхронизации с установщиком / получателем.