2017-02-08 9 views
4

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

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

Thread 1 
object.field1 = ""; 
synchronized (lock) { 
    farAwayObject.field1 = ""; 
    farAwayObject.evenFarther.field2 = ""; 
} 

Thread 2. assuming thread ordering is correct 
synchronized (lock) { 
    //thread 2 guaranteed to see all fields above as "" 
    //even object.field1 ? 
} 

Вопрос 2: Является ли object.field1 = ""; в потоке 1 неявно часть происходит, прежде, чем отношения?

Надеюсь, но это может быть и не так. Если нет, есть трюк, чтобы сделать это, не помещая его в блок синхронизации? Трудно рассуждать о программе иначе и нецелесообразно ставить все под синхронизированный {}.

EDIT: уточнение: object.field1 не является изменчивым, и вопрос заключается в том, что «будет ли нить 2 гарантированно видеть запись нитки 1, по крайней мере». Мой вопрос о видимости памяти. Для аргумента предположим, что только поток 1 записывается в нестабильный object.field1.

Вопрос 2 можно перефразировать, как

«Будет ли синхронизированный блок на замок нажимных изменения, сделанные до того, чтобы быть замеченными другими потоками синхронизации на том же замке?»

+0

Ответ на оба вопроса. – shmosel

+0

@shmosel У меня было понимание, что 'object.field1' не будет частью события-before и' Thread2' может или не может увидеть обновление? – CKing

ответ

3

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

Предполагая, что поля farAwayObject и evenFarther всегда модифицированы и accesed пути получения lock на одном объекте все вокруг вашего приложения, все потоки всегда будут видеть обновление, сделанные farAwayObject и evenFarther так synchronized навязывает происходит, прежде, чем состояние.

//thread 2 guaranteed to see all fields above as ""

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

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

Да. Mark object.field1 как volatile.


Addresing правку:

Вопрос 2 можно перефразировать

«Будет ли синхронизированный блок на замок кнопочных изменения, сделанные до того, чтобы быть видели другими потоками синхронизации на такой же замок? "

AFAIK ответ Да, при условии, что нити записи приобретают замок перед реалом нить. К сожалению, это то, что вы, как правило, не можете гарантировать, и поэтому object.field1 необходимо пометить как volatile заявление должно быть перемещено внутри блока synchronized.

Взгляните на JSR 133, который говорит о кэш смывания в основную память, когда нить выходитsyncronized блок. Это должно прояснить ситуацию.


+0

см. Мое разложение. Если я не хочу, чтобы object.field1 был изменчивым. не является конкретной записью thread1 в object.field1, нажатой в основную память, когда выполняется синхронизация (блокировка)? Если нет. это означает, что изменения памяти флагов JVM сделаны под синхронизированной блокировкой? чтобы только подтолкнуть эти изменения? – Mordan

+0

@Mordan См. Править. Это делает вещи более ясными? Дайте мне знать, если это потребует дальнейшего разъяснения. – CKing

+0

Ваша ссылка ответила на мой вопрос. Это да. Мне полегчало. :) Я искал веб в течение нескольких недель, но так и не нашел. Отличная ссылка! Спасибо. – Mordan

3

1) Когда поток входит в синхронизированный блок, барьер памяти будет включать в себя любые поля прикоснулся, а не только поля объекта, который я синхронизированного на?

Исправить. (Предположим, что нить 1 и нить 2 синхронизируются с одной и той же блокировкой.)

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

Потенциально, да. Тем не менее, это (возможно) не движение между кешами. Скорее всего, это движение от кеша процессора к памяти и от кэш-памяти второго процессора. Конечно, это зависит от того, как аппаратное обеспечение реализует иерархию памяти.

2) Is object.field1 = ""; в потоке 1 неявно является частью отношения «происходить-до»?

Существует цепочка бывает, перед тем отношения

  1. Запись в object.field1 происходит до того, как замок приобретается.
  2. Это происходит до записи в farAwayObject и так далее.
  3. Это происходит до замка освобождается от потока 1
  4. Это происходит до того, как замок приобретается потоком 2
  5. Это происходит, прежде чем нить 2 читает object.field1.

Проблема заключается в том, что произойдет, если есть промежуточная запись в object.field1, либо до того, как lock приобретаются нитью 1, или каким-либо другим поток. В любом из этих случаев цепочка происшествий не достаточна, чтобы убедиться, что поток 2 видит значение, которое было записано в потоке 1.

+0

вы можете уточнить в свете моего разъяснения. предположите, что нет промежуточных записей. Не могли бы вы ответить да, как shmosel? – Mordan

1

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

Да.

Is object.field1 = ""; в потоке 1 неявно является частью отношения «происходить-до»?

Да, даже если он нестабилен.


происходит перед заказом-частичный порядок.

Выполняемый порядок задается транзитивным замыканием синхронизаций - с ребрами и порядком программирования. Он должен быть действительным частичным порядком: reflexive, transitive и антисимметричным.

(JLS 17.4.7)

Действия перед кромкой синхронизации (т.е. Высвобождение синхронизированного замка) упорядочены по заказу программы и, таким образом синхронизированы с выпуском. Транзитивность говорит, что действия, упорядоченные , приобретают одной и той же блокировки в другом потоке, поэтому имеет порядок, предшествующий освобождению этой блокировки И действия, предшествующие выпуску этой блокировки, независимо от того, находится ли она внутри корпус блока synchronized. Важно помнить о том, что упорядочение происходит при действии (например, «Приобретение/освобождение блокировки»), а не в блоке, например, в скобках синхронизированного ключевого слова. Скобки указывают положение действий получения/выпуска, а также, когда набор действий не может чередоваться.

И, наконец, помните, что происходит - раньше это «частичный» порядок. Это означает:

  1. происходит до навязывает последовательности памяти, когда действия происходят прийти в определенном порядке (т.е. выпуск/приобретение, запись/чтение и т.д.)
  2. Случается, прежде зависит от более сильных гарантий, таких как заказ программы для получения правильная функциональность.
  3. Бывает раньше, не предотвращает ошибок, возникающих при чередовании неатомных действий.
  4. Бывает, что это транзитивная связь между действием и сильным действием. (Вы можете поместить чтение вашей общей переменной за пределы блока synchronized, пока запись идет перед блоком, и чтение приходит после блока). Более сильные гарантии заказа также выполняются перед заказом, но они также обеспечивают дополнительные эффекты, описанные в спецификации.
Смежные вопросы