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

StackOverflow https://stackoverflow.com/questions/1621495

  •  06-07-2019
  •  | 
  •  

Вопрос

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

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

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

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

Это было полезно?

Решение

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

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

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

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

Другие советы

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

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

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

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

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

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

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

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

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

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

Лицензировано под: CC-BY-SA с атрибуция
Не связан с StackOverflow
scroll top