Почему «wait» не следует вызывать, когда удерживаются несколько блокировок? - PullRequest
0 голосов
/ 24 мая 2018
  public synchronized void methodOne(List<String> profileNames, ParameterAttributes parameterAttributes) throws InterruptedException {

    if (profileNames != null && !profileNames.isEmpty()) {
      profileNames.forEach(profileName -> System.out.println(profileName));
    }
    synchronized(lockObj) {
      lockObj.wait();
    }
  }

Здесь у нас есть синхронизированный метод, и внутри метода снова у меня есть синхронизированный блок, который вызывает метод ожидания.

Ответы [ 2 ]

0 голосов
/ 24 мая 2018

Подумайте о создании локальной копии profileNames, а затем снимите блокировку перед выполнением любых операций ввода-вывода:

public void methodOne(
    List<String> profileNames, 
    ParameterAttributes parameterAttributes
) throws InterruptedException 
{
    if (profileNames != null && !profileNames.isEmpty()) {
        List<String> localNames;

        synchronized (this) {
            localNames = new ArrayList<>(profileNames);
        }
        localNames.forEach(profileName -> System.out.println(profileName));
    }

    synchronized(lockObj) {
        parameterAttributes.wait();  //NOTE: Wrong way to use wait(), but that's a topic
    }                                //      for another question.
}

Иногда вам необходимо изменить представление о том, что эффективно, а что - неэффективнокогда вы пишете многопоточный код для многопроцессорных платформ.В однопоточном коде было бы неэффективно копировать список, но повышение производительности, которое вы могли бы получить, сняв блокировку перед выполнением ввода-вывода, могло бы быть намного больше, чем попадание, которое вы получаете при создании копии.

0 голосов
/ 24 мая 2018

Что ж, пока ваш поток ожидает уведомления, он все еще удерживает другие блокировки, значительно увеличивая вероятность тупиковой ситуации.

Похоже, ваш код владеет тремя объектными мониторами:

  • объект, которому принадлежит methodOne, потому что он синхронизируется
  • lockObj, потому что вы синхронизируете его
  • parameterAttributes, потому что вы вызываете wait для него

Делаетваш код бросить исключение IllegalMonitorStateException?Я спрашиваю, потому что в примере кода не очевидно, что он на самом деле владеет монитором parameterAttributes (в примере кода нет синхронизированных (parameterAttributes)).

В любом случае, я думаю, вам нужно упростить.Владение таким количеством мониторов кажется слишком сложным.Обычно вам нужны только стратегии, синхронизированные методы или lockObj, который защищает некоторые изменяемые состояния, а не оба.Кроме того, я бы посоветовал изучить рамки актера, такие как Акка.

...