2017-02-10 8 views
1

У меня мало сомнений относительно синхронизированных блоков. Перед моими вопросами я хотел бы поделиться ответами из другого связанного сообщения Link for Answer to related question. Я цитирую Peter Lawrey из того же ответа.Нужно ли синхронизировать записи, если мы синхронизируем чтение?

  1. синхронизируется обеспечивает вас есть согласованное представление данных. Это означает, что вы прочтете последнее значение, а другие кеши получат последнее значение . Кэши достаточно умны, чтобы разговаривать друг с другом через специальную шину (но это не то, что требуется JLS, но разрешено). Эта шина означает, что она не должна касаться основной памяти, чтобы получить согласованное представление .

  2. Если вы используете только синхронизируется, то не нужно будет нестабильной. Volatile полезен, если у вас очень простая операция, для которой синхронизировано .

В связи с выше у меня есть три вопроса ниже:

Q1. Предположим, что в многопоточном приложении есть объект или примитивное поле экземпляра, которое считывается только в синхронизированном блоке (запись может происходить в каком-либо другом методе без синхронизации). Также синхронизированный блок определен на каком-то другом объекте. Является ли объявление его изменчивым (даже если оно считывается внутри только синхронизированного блока) имеет смысл?

Q2. Я понимаю, что значение состояний объекта, на котором выполнена Синхронизация, является последовательным. Я не уверен, что состояние других объектов и примитивных полей считывается сбоку в синхронизированном блоке. Предположите, что изменения сделаны без получения блокировки, но чтение выполняется путем получения блокировки. Содержит ли состояние всех объектов и значение всех примитивных полей внутри синхронизированного блока.?

Q3. [Обновить]: Будут ли считаться все поля, считываемые в синхронизированном блоке, из основной памяти независимо от того, что мы заблокировали? [ответил CKing]

У меня есть подготовленный ссылочный код для моих вопросов выше.

public class Test { 
    private SomeClass someObj; 
    private boolean isSomeFlag; 
    private Object lock = new Object(); 
    public SomeClass getObject() { 
     return someObj; 
    } 
    public void setObject(SomeClass someObj) { 
     this.someObj = someObj; 
    } 
    public void executeSomeProcess(){ 
     //some process... 
    } 
    // synchronized block is on a private someObj lock. 
    // inside the lock method does the value of isSomeFlag and state of someObj remain consistent? 

    public void someMethod(){ 
     synchronized (lock) { 
       while(isSomeFlag){ 
        executeSomeProcess(); 
       } 
       if(someObj.isLogicToBePerformed()){ 
        someObj.performSomeLogic(); 
       } 
     } 
    } 
    // this is method without synchronization. 
    public void setSomeFlag(boolean isSomeFlag) { 
     this.isSomeFlag = isSomeFlag; 
    } 
} 
+1

Я хотел бы быть приятным в этом, но это одна из тех вещей, где честность лучше всего работает. Если вы думаете о таких вещах, как «извлечения из памяти» во время разговора о JMM, вы этого не поняли и следует избегать параллелизма. Но код не указан неверно. – Voo

+0

сделать 'isSomeFlag' volatile исправить это – ControlAltDel

+0

@ Voo Я отредактировал мой вопрос, извините за использование слова памяти, я имел в виду согласованный .. –

ответ

2

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

Q1. Предположим, что в многопоточном приложении есть объект или примитивное поле экземпляра, которое считывается только в синхронизированном блоке (запись может происходить в каком-либо другом методе без синхронизации). Также синхронизированный блок определен на каком-то другом объекте. Является ли объявление его изменчивым (даже если оно считывается внутри только синхронизированного блока) имеет смысл?

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

Предположим, что изменения сделаны без фиксации, но чтение осуществляется путем получения блокировки. Содержит ли состояние всех объектов и значение всех примитивных полей внутри синхронизированного блока. ?

Ответ по-прежнему нет. Обоснование такое же, как и выше.

Итог: Изменение значений вне синхронизированного контекста не гарантирует, что эти значения будут сброшены в основную память. (поскольку поток читателя может войти в синхронизированный блок до того, как поток записи будет выполнен). Темы, которые читают эти значения в контексте synchronized, могут по-прежнему считывать старые значения, даже если они получают эти значения из основной памяти.


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

+0

Хорошо, но как насчет связанного ответа, он говорит: 1. синхронизированный гарантирует, что у вас есть последовательное представление данных. Это означает, что вы будете читать последнее значение, а другие кеши будут иметь последнее значение. и 2. Если вы используете только синхронизированный, вам не понадобится изменчивость. Летучие полезны, если у вас очень простая операция, для которой синхронизация будет чрезмерной. Являются ли они не совсем неправильными или полными? –

+1

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

+0

okk .. это полезно –

1

Все synchronized делает захват блокировки объекта, который он синхронизируется на. Если блокировка уже захвачена, она будет ожидать ее освобождения. Он никоим образом не утверждает, что внутренние поля этого объекта не изменятся. Для этого есть volatile

+0

Спасибо за ответ, я ошибочно использовал основную память, я отредактировал вопрос .. –

1

При синхронизации на объект мониторе A, это гарантирует, что другой поток синхронизация на тот же монитор A впоследствии будет видеть любых изменений, сделанных в первой нити любого объекта. Это гарантия видимости, предоставляемая synchronized, не более того.

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

+0

спасибо за ответ. Если предположить, что синхронизация была выполнена на мониторе «ObjectA», и мы читаем состояние «ObjectB» (оно модифицируется каким-либо другим методом некоторым потоком) внутри синхронизированного блока, будет ли оно последовательным? –

+1

Только если изменения в 'ObjectB' не были сделаны в блоке' synchronized (ObjectA) '. Тот же монитор -> изменяется видимым. Различные мониторы -> нет гарантии. – Kayaman

+0

Великий .. На самом деле это нечто очень близкое к тому, что я хотел знать. Просто для того, чтобы задать себе один вопрос: видимы ли изменения во всех полях (а не только объекте, на котором выполняется синхронизация), если изменения выполняются на одном мониторе? –

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