Безопасно ли получить доступ к объекту X внутри синхронизированного блока, определенного для объекта Y? - PullRequest
0 голосов
/ 03 мая 2020

Есть ответы на вопрос, является ли доступ к состоянию объекта безопасным в рамках синхронизированного метода или блока. Мой вопрос: Безопасно ли получить доступ к объекту X в синхронизированном блоке, где синхронизированный блок находится на другом объекте Y, и есть несколько записывающих потоков, присутствующих для X?

public class X{
    private int value = 0;
    /** set method will be invoked by multiple threads**/
    public void set(int v){
       this.value = v;
   }
   public int value(){
       return value;
   }
}

public class Tester{
    private final Object Y = new Object();
    public void test(X x){
        synchronized(Y){
            System.out.println(x.value()); // is it guaranteed that x.value will be read from memory and not from the current thread's cache ?
        }
    }
}      

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

Ответы [ 2 ]

2 голосов
/ 03 мая 2020

ИМО вы задаете не тот вопрос. Модель памяти Java не касается объектов и классов. В нем говорится только о видимости переменных .

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

Так, в вашем примере, если у вас есть X my_x, и некоторый поток A делает это:

synchronized(Y) {
    my_x.set(55);
}

Затем, когда какой-то другой поток B впоследствии вызывает tester.test(my_x), поток B увидит значение, которое было сохранено потоком A.

С другой стороны , если поток A вызывает my_x.set(...) без синхронизации на Y, то Java не обещает, когда, если вообще когда-либо, поток B увидит изменение.


Примечание. Ваша программа открыто вызывает сбой, создав объект блокировки, Y, член private класса Tester, а функцию test(X) public. Это практически уносит вас (или другого программиста) с ошибкой вызова tester.test(some_random_X), где some_random_X был установлен другим потоком, который не блокирует Y.

0 голосов
/ 03 мая 2020

Нет, это не безопасно.

Не имеет отношения к вопросу:

Первая проблема с примером кода:

public void set(int v){
    this.value = v;
}

это очень плохое качество кода и должно на самом деле можно написать так:

public final void setValue(final int value) {
    this.value = value;
}

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

Вторая проблема с пример кода:

public int value(){
    return value;
}

правильный шаблон проектирования для геттера:

public final int getValue() {
    return value;
}

Третья проблема с примером кода:

private final Object Y = new Object();

поле 'Y 'не является stati c и, следовательно, не является константой, правильное соглашение об именах для этого поля будет следующим:

private final Object y = new Object();

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

){

, вы действительно должны делать:

) {
Добро пожаловать на сайт PullRequest, где вы можете задавать вопросы и получать ответы от других членов сообщества.
...