Если более одного потока могут получить доступ к полю, должно ли оно быть помечено как изменчивое?

Чтение нескольких потоков (общий проблемы параллелизма, изменчивое ключевое слово, модель памяти). Меня смущают проблемы параллелизма в Java.

У меня много полей, к которым обращаются более чем один поток. Следует ли мне просмотреть их и отметить все как изменчивые?

При создании класса я не знаю, будут ли к нему обращаться несколько потоков, поэтому, конечно, небезопасно позволять любому полю not быть изменчивым, поэтому, насколько я понимаю, очень мало случаев, когда вы бы не использовали Это. Это правильно?

Для меня это характерно для JVM версии 1.5 и более поздних, но я не чувствую себя ограниченным ответом на мои конкретные настройки.


person Pool    schedule 25.10.2009    source источник


Ответы (4)


Если к полю обращается несколько потоков, оно должно быть volatile или final, или доступ к нему осуществляется только с помощью синхронизированных блоков. В противном случае присвоенные значения могут быть не видны другим потокам.

Класс должен быть специально разработан для одновременного доступа нескольких потоков. Простая маркировка полей volatile или final недостаточно для обеспечения безопасности потоков. Существуют проблемы согласованности (атомарность изменений в нескольких полях), проблемы с межпотоковой передачей сигналов (например, с использованием wait и notify) и т. Д.

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

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

person erickson    schedule 25.10.2009

Что ж, вы прочитали эти другие вопросы, и я полагаю, вы уже прочитали ответы, поэтому я просто выделю несколько ключевых моментов:

  1. они изменятся? в противном случае вам не нужны летучие
  2. если да, то связано ли значение одного поля с другим? если да, переходите к пункту 4
  3. сколько потоков поменяет это? если только 1, то volatile - это все, что вам нужно
  4. если ответ на номер 2 - «нет» или несколько потоков собираются писать в него, то одного volatile недостаточно, вам, вероятно, потребуется синхронизировать доступ

Добавлено:
Если поле ссылается на объект, то у него будут собственные поля, и все эти соображения также применимы к этим полям.

person RichN    schedule 25.10.2009

Если нужно спросить, используйте замки. volatile может быть полезен в некоторых случаях, но сделать это очень и очень сложно. Например:

class Foo {
  private volatile int counter = 0;
  int Increment() {
    counter++;
    return counter;
  }
}

Если два потока запускаются Increment() одновременно, результат может быть counter = 1. Это потому, что компьютер сначала извлечет counter, добавит его, а затем сохранит обратно. Volatile просто заставляет сохранение и загрузку происходить в определенном порядке относительно других операторов.

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

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

person bdonlan    schedule 25.10.2009
comment
Для этого конкретного случая использования см. AtomicInteger, вместо того, чтобы использовать synchronized самостоятельно. - person erickson; 25.10.2009
comment
Верно. Я просто хотел продемонстрировать подводные камни слепого использования synchronized, не понимая, что именно он делает, а что не дает. - person bdonlan; 25.10.2009

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

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

person Yishai    schedule 25.10.2009