Aqui está um exemplo, porque um exemplo geralmente é mais claro do que uma explicação longa. Suponhamos que foo
é uma variável do tipo long
. A operação a seguir não é uma operação atômica:
foo = 65465498L;
De fato, a variável é escrita usando duas operações separadas: uma que escreve os primeiros 32 bits e a segunda que escreve os últimos 32 bits. Isso significa que outro encadeamento pode ler o valor de foo
e ver o estado intermediário.
Tornar a operação atômica consiste em usar mecanismos de sincronização para garantir que a operação seja vista, a partir de qualquer outro encadeamento, como uma única operação atômica (isto é, não dividida em partes). Isso significa que qualquer outro encadeamento, uma vez que a operação seja atômica, verá o valor de foo
antes da atribuição ou após a atribuição. Mas nunca o valor intermediário.
Uma maneira simples de fazer isso é tornar a variável volátil :
private volatile long foo;
Ou para sincronizar todos os acessos à variável:
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
Ou, para substituí-lo por um AtomicLong
:
private AtomicLong foo;