Вот пример, потому что пример часто яснее, чем длинное объяснение. Предположим foo
, это переменная типа long
. Следующая операция не является атомарной операцией:
foo = 65465498L;
Действительно, переменная записывается с использованием двух отдельных операций: одна записывает первые 32 бита, а вторая - последние 32 бита. Это означает, что другой поток может прочитать значение foo
и увидеть промежуточное состояние.
Создание операции атомарной состоит в использовании механизмов синхронизации, чтобы убедиться, что операция рассматривается из любого другого потока как отдельная атомарная (т.е. не разделяемая на части) операция. Это означает, что любой другой поток после выполнения атомарной операции будет видеть значение foo
до или после назначения. Но никогда не промежуточное значение.
Простой способ сделать это - сделать переменную volatile :
private volatile long foo;
Или синхронизировать каждый доступ к переменной:
public synchronized void setFoo(long value) {
this.foo = value;
}
public synchronized long getFoo() {
return this.foo;
}
// no other use of foo outside of these two methods, unless also synchronized
Или заменить его на AtomicLong
:
private AtomicLong foo;