Будет ли следующий код успешно выполняться? - PullRequest
0 голосов
/ 12 сентября 2018

В практике параллелизма Java Брайана Гетца есть следующий пример, который объясняет повторяемость блокировок в Java как:

public class Widget {
  public synchronized void doSomething() {
    ...
  }
}

public class LoggingWidget extends Widget {
  public synchronized void doSomething() {
    System.out.println(toString() + ": calling doSomething");
    super.doSomething();
  }
}

В нем говорится, что из-за повторного появления блокировок в Java приведенный выше код не приведет к взаимоблокировке, поскольку блокировки достигаются для каждого потока, а не для каждого вызова.

Однако, если мы немного повернём пример, как:

public class XYZ {
  public synchronized void someFunction() {
    ...
  }
}

public class SomeClass {
  private XYZ xyz;
  ...
  public synchronized void functionCalled() {
    ...
    xyz.someFunction();
  }
}

Мы вызываем функциюCalled () для SomeClass, и блокировка получается для объекта SomeClass. Теперь, будет ли вызван someFunction () или, другими словами, поток войдет в someFunction () класса xyz. Будет ли синхронизированная функция класса XYZ запрашивать блокировку для объекта класса XYZ? Я немного смущен. Пожалуйста, уточните.

Ответы [ 2 ]

0 голосов
/ 12 сентября 2018

Самый простой способ понять, удастся он или нет - просто запустить его.Я переписал ваш код в рабочий пример, и в обоих случаях он действительно выводит «Hello».

public class XYZ {

  public void someFunction() {
    synchronized (this) {
        System.out.println("Hello");
    }
  }
}

public class SomeClass {
  private XYZ xyz = new XYZ();

  public void functionCalled() {
    synchronized (this) {
      xyz.someFunction();
    }
  }

  public static void main(String[] args) {
    new SomeClass().functionCalled();
  }
}

Я также переписал ваши методы для использования блоков синхронизации.Они работают так, что никакие потоки не могут войти в блок, если внутри него находится другой поток, и объект (блокировка) одинаков.Здесь вы можете видеть, что обе функции синхронизируются по this, что относится к двум разным объектам, поскольку эти два метода принадлежат двум разным классам.Здесь нет конфликта.

functionCalled синхронизируется по экземпляру SomeClass

someFunction синхронизируется по экземпляру XYZ

Это отличается от примерав твоей книге я думаю, что смысл примера в том, что на самом деле замки одинаковы!В некоторых средах это может вызвать взаимоблокировку, но, как указано, не в Java.Возьмите этот пример.

public class XYZ {

  public void someFunction() {
    synchronized (this) {
        System.out.println("Hello");
    }
  }
}

public class SomeClass {
  private XYZ xyz = new XYZ();

  public void functionCalled() {
    synchronized (xyz) {
      xyz.someFunction();
    }
  }

  public static void main(String[] args) {
    new SomeClass().functionCalled();
  }
}

Может выглядеть похоже, но в этом случае functionCalled синхронизируется по тому же объекту, иначе.они используют тот же объект, что и замок!Дело в том, что текущий поток уже имеет блокировку на объекте, поскольку блокировки основаны на отдельных потоках, поэтому он может безопасно войти в синхронизированный блок и не пытается снова получить блокировку.Если бы он получал блокировку для каждого вызова, он попытался бы снова получить блокировку и застрял, так как первый вызов уже владеет блокировкой.

0 голосов
/ 12 сентября 2018

Да, приведенный выше код будет запрашивать блокировку как для SomeClass, так и для объекта xyz.Однако это не вызывает никаких проблем.

Объект xyz имеет значение private, поэтому нет никакой возможности, что какой-либо поток сначала заблокирует xyz перед вызовом functionCalled(), таким образом, нет возможности мертвой блокировкитак как две блокировки здесь всегда вызываются в порядке SomeClass -> xyz.

...