O que significa "atômico" na programação?

276

No livro Java efetivo, ele afirma:

A especificação da linguagem garante que a leitura ou gravação de uma variável seja atômica, a menos que a variável seja do tipo longou double[JLS, 17.4.7].

O que significa "atômico" no contexto da programação Java ou programação em geral?

James
fonte
24
Uma operação de cada vez.
Subhrajyoti Majumder
1
somente uma operação pode ser executada na variável por vez.
kaysush
1
Eu suspeito que questões de filosofia pertençam a codereview.stackexchange.com
Phlip 3/14/14
Observando que algumas variáveis ​​não possuem, por padrão, leitura e gravação atômicas, declarando-as como volatile longou volatile doubletornando a leitura atômica e a gravação atômica.
H2ONaCl 25/10/19

Respostas:

372

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 fooe 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 fooantes 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;
JB Nizet
fonte
75
Portanto, isso pressupõe que esteja sendo executado em um sistema de 32 bits. E se fosse um sistema de 64 bits? Será foo = 65465498L; ser atômico então?
Harke
46
@ Harke Se você estiver executando Java de 64 bits, sim.
Jeroen #
4
Isso se aplica também a C # e .NET? Se sim, para obter um comportamento atômico, o CLR deve ser de 64 bits?
Fabiano
5
@ Fabiano Aplica-se e aqui está como alcançá-lo no .NET, pois não temos a palavra-chave sincronizada como Java. stackoverflow.com/questions/541194/…
The Muffin Man
2
Então, vamos supor que o segmento A atribua um valor longo e, a meio caminho, o segmento B tenta lê-lo. Se a operação A for atômica, o encadeamento B esperará até terminar? Isso significa que as operações atômicas fornecerão segurança de thread implícita?
Teoman shipahi
60

"Operação atômica" significa uma operação que parece instantânea da perspectiva de todos os outros threads. Você não precisa se preocupar com uma operação parcialmente completa quando a garantia se aplica.

H2ONaCl
fonte
25

É algo que "parece que o resto do sistema ocorre instantaneamente" e se enquadra na categorização de Linearizabilidade nos processos de computação. Para citar mais esse artigo vinculado:

A atomicidade é uma garantia de isolamento de processos concorrentes. Além disso, as operações atômicas geralmente têm uma definição de êxito ou falha - elas alteram com êxito o estado do sistema ou não têm efeito aparente.

Assim, por exemplo, no contexto de um sistema de banco de dados, é possível ter 'confirmações atômicas', o que significa que você pode enviar um conjunto de alterações de atualizações para um banco de dados relacional e essas alterações serão todas enviadas ou nenhuma no caso de falha, dessa maneira os dados não se corrompem e, consequentemente, de bloqueios e / ou filas, a próxima operação será uma gravação ou leitura diferente, mas somente após o fato. No contexto de variáveis ​​e encadeamento, isso é o mesmo, aplicado à memória.

Sua cotação destaca que esse comportamento não precisa ser esperado em todas as instâncias.

Grant Thomas
fonte
15

Acabei de encontrar um post Operações atômicas vs. operações não atômicas para ser muito útil para mim.

"Uma operação que atua na memória compartilhada é atômica se for concluída em uma única etapa em relação a outros threads.

Quando um armazenamento atômico é executado em uma memória compartilhada, nenhum outro encadeamento pode observar a modificação pela metade.

Quando uma carga atômica é executada em uma variável compartilhada, ele lê o valor inteiro como apareceu em um único momento no tempo ".

Kurt Zhong
fonte
14

Se você tiver vários threads executando os métodos m1 e m2 no código abaixo:

class SomeClass {
    private int i = 0;

    public void m1() { i = 5; }
    public int m2() { return i; }
}

você tem a garantia de que qualquer chamada de thread m2será 0 ou 5.

Por outro lado, com este código (onde ié um longo):

class SomeClass {
    private long i = 0;

    public void m1() { i = 1234567890L; }
    public long m2() { return i; }
}

uma chamada de encadeamento m2pode ler 0, 1234567890L ou algum outro valor aleatório, porque i = 1234567890Lnão é garantido que a instrução seja atômica para a long(uma JVM pode gravar os primeiros 32 bits e os últimos 32 bits em duas operações e um encadeamento pode ser observado ino meio) .

assylias
fonte
por que você acha que "long" causa problemas enquanto "int" não? Por favor, veja aqui geekswithblogs.net/BlackRabbitCoder/archive/2012/08/09/…
onmyway133
1
As atribuições longas e duplas do @entropy não são garantidas como atômicas em Java. Então você pode ler um longo artigo em que apenas metade dos bits foi atualizada após uma atribuição.
assylias 26/09/13
0

Em Java, os campos de todos os tipos de leitura e gravação, exceto long e double, ocorrem atomicamente, e se o campo for declarado com o modificador volátil, mesmo long e double serão lidos e gravados atomicamente. Ou seja, obtemos 100% do que estava lá ou do que aconteceu lá, nem pode haver nenhum resultado intermediário nas variáveis.

Eugene Shamkin
fonte