Потокобезопасность в классе Java - PullRequest
15 голосов
/ 30 августа 2010

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

class TestClass {  
   private int x;

   int get() {
       return x;
   }

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

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

Ответы [ 4 ]

11 голосов
/ 30 августа 2010

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

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

8 голосов
/ 30 августа 2010

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

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

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

Пожалуйста, прочитайте «Память и блокировки» * глава 1008 *спецификации языка Java.

5 голосов
/ 30 августа 2010

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

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

1 голос
/ 01 сентября 2010

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

synchronized int getAndSet(int x, boolean set) {
    if (set) this.x = x;
    return this.x;   // param x is for set
} 
Добро пожаловать на сайт PullRequest, где вы можете задавать вопросы и получать ответы от других членов сообщества.
...