2010-08-30 2 views
15

Почему этот класс Java не является потокобезопасным.Безопасность потоков в Java-классе

class TestClass { 
    private int x; 

    int get() { 
     return x; 
    } 

    void set(int x) { 
     this.x = x; 
    } 
} 

Я прочитал, что ключевое слово synchronized необходимо, чтобы сделать его поточно? В конце концов, это не операции, выполняемые внутри атома?

+1

private void int x? –

ответ

11

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

Вы можете синхронизировать свой код должным образом, синхронизировавшись на мониторе (используя синхронизированное ключевое слово или блокировку java.util.concurrent), или объявив x неустойчивым.

+0

Точно так же в C# тоже? – devnull

8

С несколькими процессорами некоторые значения могут быть кэшированы процессором и могут не отражать изменения, сделанные другими потоками/процессорами для одних и тех же объектов. На самом деле JVM может быть реализован таким образом, чтобы работать с одним процессором.

Синхронные методы явно требуют спецификации языка для представления барьера памяти и требуют перечитать все переменные экземпляра из памяти.

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

Просьба ознакомиться с главой спецификации языка Java 'Memory and Locks'.

+1

Причина для downvote? –

5

Поскольку поле 'x' не объявлено изменчивым, для JVM не требуется гарантировать, что 'x' будет видимым для всех других потоков. То есть если один поток постоянно читает значение «x», а другой поток записывает его, возможно, что поток чтения никогда не «увидит» изменение значения.

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

1

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

synchronized int getAndSet(int x, boolean set) { 
    if (set) this.x = x; 
    return this.x; // param x is for set 
}