Java энергозависимый переменный вопрос

При чтении этой статьи DZone о параллелизме Java я задавался вопросом если следующий код:


    private volatile List list;
    private final Lock lock = new ReentrantLock();

    public void update(List newList) {
        ImmutableList l = new ImmutableList().addAll(newList);
        lock.lock();
        list = l;
        lock.unlock();
    }

    public List get() {
        return list;
    }

эквивалентно:


    private volatile List list;

    public void update(List newList) {
        ImmutableList l = new ImmutableList().addAll(newList); 
        list = l;
    }

    public List get() {
        return list;
    }

Попытка {} наконец {} блок была опущена для краткости. Я предполагаю, что класс ImmutableList действительно неизменная структура данных, которая содержит ее собственные данные, такие как тот, обеспеченный в библиотеке наборов Google. Так как переменная списка энергозависима и в основном что продолжается, copy-on-the-fly, не это безопасный просто пропустить при использовании блокировок?

9
задан teto 3 February 2010 в 17:37
поделиться

6 ответов

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

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

6
ответ дан 4 December 2019 в 15:18
поделиться

Я думаю, что поведение синхронизации по умолчанию volatile не гарантирует поведение ReentrantLock, поэтому оно может помочь с производительностью. В остальном, думаю, нормально.

0
ответ дан 4 December 2019 в 15:18
поделиться

После повторного прочтения "да" они эквивалентны.

1
ответ дан 4 December 2019 в 15:18
поделиться

Если мы говорим о времени и видимости памяти. Волатильное считывание очень близко к тому времени, которое требуется для нормального считывания. Так что если вы делаете get() alot, то разница небольшая. Время, необходимое для записи волатильности, составляет около 1/3 времени для получения и освобождения блокировки. Так что ваше второе предложение немного быстрее.

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

.
1
ответ дан 4 December 2019 в 15:18
поделиться

Да, оба этих примера кода ведут себя одинаково в параллельной среде. Неустойчивые поля никогда не кэшируются локально для потока , поэтому после того, как один поток вызывает update (), который заменяет список новым списком, get () для всех других потоков вернет новый список.

Но если у вас есть код, который использует его следующим образом:

list = get()
list = list.add(something) // returns a new immutable list with the new content
update(list)

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

4
ответ дан 4 December 2019 в 15:18
поделиться

Дополнительные предметы для добавления в список без особого порядка:

  • Производительность - задержка, полоса пропускания, масштабирование или другие факторы, связанные с поставляемым продуктом
  • Поддержка - У вас уже есть журнал, но как насчет сантехники в других диагностических измерениях (Java-JMX, Windows-WMI/счетчики производительности или что-то пользовательское)
  • Гибкость - трудности при изменении архитектуры позже (обычно это одна из тех вещей, которые чрезмерно выполняются и вызывают больше проблем, чем необходимо, но обсуждение должно присутствовать при оценке дизайна)
  • Модель многопоточности/модель блокировки - Ясно ли, как данные будут защищены? Как будет обрабатываться конфликт ресурсов?
  • Требования к ресурсам - потребление памяти на различных уровнях использования. Соответствует ли он вашим ограничениям?
  • Обработка ошибок - Когда что-то в продукте выходит из строя, поддерживает ли архитектура чистую обработку и уведомление о проблемах?
  • Понятно - Слишком сложные архитектуры, как правило, забываются во время реализации. Если большинство команды, и в особенности руководители, не могут сохранить архитектуру, это философия и правила, в голове, архитектура не будет иметь значения.
  • Согласованность. Пытается ли он использовать все возможные образцы или сосредоточиться на регулярных, повторяющихся узорах. Не то чтобы выбор правильного образца для каждой проблемы не является хорошей вещью, но наличие большого количества узоров может повлиять на понятность и привести к ошибкам реализации. Архитектор должен стараться демонстрировать все, что он знает (или самую последнюю классную вещь) в каждом проекте.
  • Тестопригодность - помогает ли проект тестированию (системе и интеграции). Может ли тестирование быть автоматизированным или вы будете полагаться на армию тестеров, чтобы постоянно повторять регрессионное тестирование, чтобы вы знали, что ваша команда не сломала продукт?
  • Действительно ли архитектура решает проблему, которую вы пытаетесь решить, и в рамках этой проблемы? Не создавайте скребок, когда будет достаточно дуплексного режима.
-121--4859578-

Но в первом случае нет противоречий.

extern int i;
extern double i;

тоже не сработает. Так что если вы создадите класс А, то не сможете решить, кто такой А.

-121--3772226-

Для обеспечения требуемой безопасности потока необходимо выполнить следующие критерии:

  1. Записи в переменную не зависят от ее текущего значения.
  2. Переменная не участвует в инвариантах с другими переменными.

Поскольку здесь встречаются оба - код - безопасность потоков

1
ответ дан 4 December 2019 в 15:18
поделиться