Этот код не является потокобезопасным - должен ли он быть? - PullRequest
0 голосов
/ 08 января 2019

У меня есть класс, который сильно упрощен для соответствующих частей и выглядит так (фиктивные имена):

@RequiredArgsConstructor
public class SomeClass {
   private final SomeProvider someProvider;
   private SomeDataStore store = null;

   private SomeDataStore getStoreAttributes() {
      if (store == null) {
          store = new SomeDataStore(someProvider, <other params>)
      }
      return store;
   }
}

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

Есть ли какие-либо проблемы, которые я пропускаю с безопасностью потока этого?

Спасибо!

Ответы [ 3 ]

0 голосов
/ 08 января 2019

В данном примере, если есть несколько потоков, вызывающих метод - «getStoreAttributes ()», тогда переменная экземпляра «store» может быть инициализирована дважды. Если в вашем случае хорошо инициализировать переменную хранилища несколько раз, тогда это нормально, не нужно добавлять никакой безопасности потока. Если вы не хотите добавлять функции безопасности потоков, такие как синхронизированный блок, по крайней мере, сделайте переменную «store» volatile, которая будет гарантировать, что потоки будут читать свое последнее состояние из памяти.

Но название «store» выглядит как некий ресурс, и его многократная инициализация без всякой причины кажется неправильной. И вы можете сохранить это, добавив безопасность потоков. Если один поток инициализирует ресурс, другой будет ждать и использовать инициализированный ресурс. Вы можете реализовать двойную блокировку, чтобы гарантировать то же самое.

0 голосов
/ 08 января 2019

Есть ли какие-либо проблемы, которые я пропускаю с безопасностью потока этого?

Да. По крайней мере, это:

  • если у вас есть экземпляр SomeClass, который совместно используется двумя или более потоками, по крайней мере один из этих потоков когда-либо устанавливает элемент store в значение, отличное от null, и любой другой поток вызывает getStoreAttributes() в этом случае, тогда у вас есть гонка данных . В этом случае поведение вашей программы не определено.

  • среди поведения, которое можно наблюдать на практике при такой гонке данных, как

    • один или несколько потоков никогда наблюдать обновление до store
    • различные потоки наблюдают за обновлением до store в порядке, который кажется несовместимым
  • Даже если бы вы могли предположить, что чтение и запись в store были атомарными, так что не было гонки данных, у вас все еще возникла бы проблема, которую могли наблюдать оба разных потока store будет null и одновременно ввести блок if. В результате каждый из них будет создавать новый SomeDataStore, который будет возвращать метод, нанося поражение очевидной цели.

0 голосов
/ 08 января 2019

Короткий ответ: вы должны стремиться писать свой код так, чтобы он был поточно-ориентированным. Теперь длинный ответ: насколько вы можете судить, у вашего кода сейчас нет проблем из-за этой небезопасной операции. Предполагая, что вы вундеркинд и правильно оценили текущую ситуацию, допустив это в своей кодовой базе, вы добавили некоторую форму долга, некоторую часть кода, которая может легко оказаться проблематичной в будущем и может стать трудной для поиска. ошибок. Трудно сказать, но я вижу, что вы пытаетесь создать кэшированное поле, есть способы сделать этот поток безопасным.

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