Это плохая идея использовать getClass () для синхронизации при инициализации частной статической переменной? - PullRequest
0 голосов
/ 22 марта 2019

Так вот в чем проблема. У меня есть следующий абстрактный класс.

  public abstract class JAXBParser<T> {

  private static final Object lock = new Object();

  private static volatile JAXBContext context;

  private JAXBContext getContext() {
    if (context == null) {
      synchronized (getClass()) {
        if (context == null) {
          try {
            context = JAXBContext.newInstance(getJAXBClass());
          } catch (JAXBException e) {
            log.error("Couldn't create JAXB context", e);
          }
        }
      }
    }

    return context;
  }

  @SuppressWarnings("unchecked")
  public Optional<T> parse(File file) {
    log.debug(file.getAbsolutePath());
    try {
      JAXBContext context = getContext();
      Unmarshaller unmarshaller = context.createUnmarshaller();

      return Optional.ofNullable((T) unmarshaller.unmarshal(file));
    } catch (JAXBException e) {
      log.error(unmarshallerError(file.getAbsolutePath()), e);
    }

    return Optional.empty();
  }

  protected abstract Class getJAXBClass();
}

Идея состоит в том, что у меня будет пара синтаксических анализаторов с одинаковым поведением, поэтому я могу использовать это, чтобы следовать принципу СУХОЙ (и играть с наследованием, многопоточностью, синхронизацией и т. Д.). Также в этом вопросе указано, что инициализация JAXBContext является тяжелой, поэтому было бы неплохо инициализировать ее один раз. Поэтому я решил инициализировать его один раз для каждого дочернего класса, используя двойную проверку блокировки.

Вопрос в следующем:

Это плохая идея использовать getClass () для синхронизации? Было бы лучше использовать объект блокировки и почему?

Ответы [ 2 ]

2 голосов
/ 22 марта 2019

Экземпляр Class также является Object, для него вполне допустима синхронизация.

Однако, поскольку существует только один экземпляр, вы не сможете различить разные (несвязанные) синхронизированные разделы, если вам понадобится более одного в будущем.

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

1 голос
/ 22 марта 2019

У блокировки публично видимых объектов есть одна большая проблема: вы не можете рассуждать о поведении класса в изоляции.

Причина в том, что другие части кода также могут синхронизироваться с вашим объектом класса, что может привести к тому, что ваш метод getContext() будет блокироваться бесконечно.

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

* Предполагается, что вредоносного кода нет. Если вы действительно этого хотите, вы можете делать действительно неприятные вещи, синхронизируя по невольно разделяемым объектам, как этот пример , который я создал, который «незаметно» соединяет входной и выходной потоки.

Добро пожаловать на сайт PullRequest, где вы можете задавать вопросы и получать ответы от других членов сообщества.
...