Каково различие между синхронизируемым на 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 и использованием этого как блокировка? Это, кажется, то же мне..

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

47
задан Gray 25 January 2017 в 00:45
поделиться

5 ответов

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

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

64
ответ дан 26 November 2019 в 19:42
поделиться

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

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

1
ответ дан 26 November 2019 в 19:42
поделиться

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

5
ответ дан 26 November 2019 в 19:42
поделиться

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

Вот пример кода, который блокирует даже «быстрые» 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 -синхронизированные методы и вы ничего не можете сделать (в своем классе), чтобы запретить это во время выполнения. Чтобы избежать этой потенциальной ловушки, вы должны синхронизировать закрытый конечный объект или использовать интерфейс Lock в java.util.concurrent.locks .

В этом простом примере вы можете альтернативно использовать AtomicInteger вместо синхронизации установщика / получателя.

12
ответ дан 26 November 2019 в 19:42
поделиться

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

0
ответ дан 26 November 2019 в 19:42
поделиться
Другие вопросы по тегам:

Похожие вопросы: