2016-06-05 4 views
3

Мне нужно только отметить поле volatile, если несколько потоков читают его в то же время?Нужно ли мне ключевое слово volatile? (Java)

Как насчет сценария, когда Thread A изменяет значение поля, и Thread B оценивает его после завершения Thread A?

В моем сценарии есть ли какие-либо действия до вступления в силу (без ключевого слова volatile)?

+1

https://www.cs.umd.edu/~pugh/java/memoryModel/jsr-133-faq. html # volatile Стоит прочитать все. – pvg

+2

, если поток B выполнил A.join(), тогда чтение переменной дает значение, записанное потоком A, и переменная не должна быть изменчивой. –

+2

Как гарантировано, что поток A закончен, с точки зрения B? – hyde

ответ

5

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

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

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

В случае Вашего первоначального вопроса, некоторые способы надлежащей синхронизации может быть Достигнутые с помощью volatile ключевого слова, с помощью synchronized блоков, или при наличии потока, который читает значение переменной join() потока, в котором переменная написана.

Edit: В ответ на ваш комментарий, Future имеет внутреннюю синхронизацию, например, что вызов Get() на будущем учреждает «происходит до» отношений, когда вызов возвращается, так что и обеспечивает правильную синхронизацию.

+2

Просто одно важное уточнение: вам не нужна нить B для запуска на другом процессоре, чтобы иметь проблемы с видимостью памяти (другими словами, это может происходят и на одноядерных процессорах). Одной из практических причин является оптимизация JIT/Hotspot, приводящая к коду, который сохраняет определенные значения в регистрах ЦП без чтения или записи в память. Вам нужно, чтобы правильные * происшествия до * отношений косвенно указывали оптимизатору пределы. – Holger

+0

@ Holger Согласен. Я приводил простой пример, так как иногда люди, которые не знакомы с многопоточным процессом, скептически относятся к тому, почему синхронизация требуется, когда задействованы макроскопические истекшие времена. –

+0

Означает ли это, что синхронизированный блок заставляет все написанное внутри него записываться в основную память, когда поток выходит из него? –

0

Нет, вам не нужно volatile ...

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

... но ваш код должен сделать что-то установить «происходит-прежде.»

Там будет происходит, прежде, чем отношения, если (и только если) ваш код делает что-то, что «Спецификация языка Java» (JLS) говорит, что установит «происходит-прежде.»

Как насчет сценария, когда Thread A изменяет значение поля, а Thread B оценивает его после завершения Thread A?

В зависимости от того, что вы подразумеваете под "гарантировано". Если «гарантировано» означает «установленное происходит раньше», тогда ваш код будет работать, как ожидалось.

Один из способов вы можете гарантировать, что для нитки B можно позвонить threadA.join(). JLS гарантирует, что если поток B вызывает threadA.join(), тогда все потоки A должны были «произойти до», когда возвращается вызов join().

Вам не нужно какой-либо из общих переменных быть volatile, если поток B обращается только к их после присоединения к нити A.

0

Вы можете выбрать один из доступных вариантов для достижения той же цели.

  1. Вы можете использовать volatile, чтобы заставить все потоки получить последнее значение переменной из основной памяти.
  2. Вы можете использовать synchronization для защиты критически важных данных
  3. Вы можете использовать API Lock
  4. Вы можете использовать переменные Atomic

Обратитесь к этой документации page на параллелизм конструкций высокого уровня.

Посмотрите на смежные вопросы SE:

Avoid synchronized(this) in Java?

What is the difference between atomic/volatile/synchronized?

Смежные вопросы