Почему этот класс Java не является поточно-безопасным.
class TestClass {
private int x;
int get() {
return x;
}
void set(int x) {
this.x = x;
}
}
Я прочитал, что ключевое слово synchronized
необходимо, чтобы сделать его потокобезопасным? В конце концов, разве операции не выполняются внутри атомарного?
Хотя само присваивание является атомарной операцией, из-за разного аппаратного обеспечения и реализации компилятора разные потоки могут видеть разные значения члена x. То есть изменение одного потока может быть невидимым для другого потока из-за какого-то кэширования. Обычно это называется проблемой видимости потока.
Вы можете правильно синхронизировать свой код, либо синхронизируя его на мониторе (используя ключевое слово synchronized или блокировки java.util.concurrent), либо объявив x volatile.
Поскольку поле "x" не объявлено изменчивым, JVM не требует, чтобы "x" был виден всем другим потокам. т.е. если один поток постоянно читает значение 'x', а другой поток записывает его, возможно, что читающий поток никогда не «увидит» изменение значения.
Синхронизированное ключевое слово не требуется, но будет работать, так как оно создаст необходимый барьер памяти/очистку кеша, чтобы обеспечить видимость «x», но использование ключевого слова volatile в этом случае будет более эффективным.
При использовании нескольких процессоров некоторые значения могут кэшироваться процессором и могут не отражать изменения, внесенные другими потоками/процессорами для тех же объектов. На самом деле, JVM может работать таким образом даже с одним процессором.
Спецификация языка явно требует, чтобы синхронизированные методы представляли барьер памяти и требовали повторного считывания всех переменных экземпляра из памяти.
Поскольку ваш код не синхронизирован, один поток может установить значение, но другой поток вернет значение, все еще кэшированное этим потоком.
Прочтите главу 'Память и блокировки' Спецификации языка Java.