Ось приклад, тому що приклад часто зрозуміліший, ніж довге пояснення. Припустимо foo
, це змінна тип long
. Наступна операція не є атомною операцією:
foo = 65465498L;
Дійсно, змінна записується за допомогою двох окремих операцій: перша, яка записує перші 32 біти, і друга, яка записує останні 32 біти. Це означає, що інший потік може прочитати значення foo
та побачити проміжний стан.
Зробити операцію атомною полягає у використанні механізмів синхронізації для того, щоб переконатися, що операція бачиться з будь-якого іншого потоку, як єдиний, атомний (тобто не розділений на частини). Це означає, що будь-який інший потік, коли операція буде зроблена атомною, буде бачити значення foo
до призначення, або після призначення. Але ніколи проміжне значення.
Простий спосіб зробити це - зробити змінну мінливою :
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;