AtomicBoolean vs Volatile boolean

244

O que AtomicBoolean faz que um booleano volátil não pode alcançar?

JeffV
fonte
16
Eu estava procurando uma resposta mais sutil para: "quais são as limitações de cada uma?". Por exemplo, se is é um sinalizador definido por um segmento e lido por um ou mais outros, não há necessidade de AtomicBoolean. No entanto, como estou vendo com essas respostas, se o thread compartilha uma variável em vários threads pode escrever e está atuando no resultado de suas leituras, o AtomicBoolean coloca em operação as operações sem travamento do tipo CAS. Estou aprendendo bastante aqui, na verdade. Felizmente, outros se beneficiarão também.
JeffV
1
possível duplicata de booleano volátil vs. AtomicBoolean
Flow
booleano volátil precisará de sincronização explícita para lidar com condições de corrida, em outras palavras, cenário como recurso compartilhado sendo atualizado (mudança de estado) por vários threads, por exemplo, contador de incremento / decremento ou inversão de booleano.
precisa saber é o seguinte

Respostas:

99

Eles são totalmente diferentes. Considere este exemplo de um volatilenúmero inteiro:

volatile int i = 0;
void incIBy5() {
    i += 5;
}

Se dois threads chamam a função simultaneamente, ipode ser 5 depois, pois o código compilado será um pouco semelhante a este (exceto que você não pode sincronizar int):

void incIBy5() {
    int temp;
    synchronized(i) { temp = i }
    synchronized(i) { i = temp + 5 }
}

Se uma variável é volátil, todo acesso atômico a ela é sincronizado, mas nem sempre é óbvio o que realmente se qualifica como acesso atômico. Com um Atomic*objeto, é garantido que todo método é "atômico".

Assim, se você usar um AtomicIntegere getAndAdd(int delta), pode ter certeza de que o resultado será 10. Da mesma forma, se dois threads negam uma booleanvariável simultaneamente, com um AtomicBooleanvocê pode ter certeza de que possui o valor original posteriormente, com um volatile boolean, você não pode.

Portanto, sempre que houver mais de um encadeamento modificando um campo, você precisará torná-lo atômico ou usar a sincronização explícita.

O objetivo de volatileé diferente. Considere este exemplo

volatile boolean stop = false;
void loop() {
    while (!stop) { ... }
}
void stop() { stop = true; }

Se você tiver um thread em execução loop()e outro chamado de thread stop(), poderá executar um loop infinito se omitir volatile, pois o primeiro thread pode armazenar em cache o valor de stop. Aqui, o volatileserve como uma dica para o compilador ter um pouco mais de cuidado com as otimizações.

Cefalópode
fonte
84
-1: você está dando exemplos, mas não está realmente explicando a diferença entre um volátil e um Atomicxxxx.
Jason S
70
A questão não é sobre volatile. A pergunta é sobre volatile booleanvs AtomicBoolean.
anta
26
-1: a pergunta feita especificamente sobre booleano, que é um caso único em comparação com outros tipos de dados e deve ser explicada diretamente.
John Haager
8
@ sgp15 Tem a ver com a sincronização a partir de Java 5.
Man of One Way
6
Se o valor booleano for lido por muitos threads, mas gravado por apenas um thread, volatile booleanserá suficiente. Se também houver muitos escritores, você pode precisar AtomicBoolean.
StvnBrkdll
263

Uso campos voláteis quando o referido campo é SOMENTE ATUALIZADO por seu encadeamento proprietário e o valor é lido apenas por outros encadeamentos; você pode pensar nele como um cenário de publicação / assinatura em que existem muitos observadores, mas apenas um editor. No entanto, se esses observadores precisarem executar alguma lógica com base no valor do campo e empurrar um novo valor para trás, seguirei com vars Atomic * ou bloqueios ou blocos sincronizados, o que melhor me convier. Em muitos cenários simultâneos, tudo se resume a obter o valor, compará-lo com outro e atualizar, se necessário, daí os métodos compareAndSet e getAndSet presentes nas classes Atomic *.

Verifique os JavaDocs do pacote java.util.concurrent.atomic para obter uma lista de classes Atomic e uma excelente explicação de como elas funcionam (apenas aprendi que elas são livres de bloqueios, para que tenham uma vantagem sobre bloqueios ou blocos sincronizados)

teto
fonte
1
@ksl Acho que @teto deseja descrever que, se apenas um segmento modificar o booleanvar, devemos escolher volatile boolean.
znlyj
2
Excelente resumo.
Ravindra babu
56

Você não pode fazer isso compareAndSet, getAndSetcomo operação atômica com booleano volátil (a menos que, é claro, você o sincronize).

Nanda
fonte
6
Isso é verdade, mas isso não seria um requisito bastante raro para um booleano?
28414 Robin
1
O @ Robin pensa em usá-lo para controlar uma invocação lenta de um método de inicialização.
Ustaman Sangat
Na verdade, eu acho que esse é um dos principais casos de uso.
fool4jesus 16/06
42

AtomicBooleanpossui métodos que executam suas operações compostas atomicamente e sem a necessidade de usar um synchronizedbloco. Por outro lado, volatile booleansó pode executar operações compostas se isso for feito dentro de um synchronizedbloco.

Os efeitos de memória da leitura / gravação volatile booleansão idênticos aos métodos gete respectivamente.setAtomicBoolean

Por exemplo, o compareAndSetmétodo executará atomicamente o seguinte (sem um synchronizedbloco):

if (value == expectedValue) {
    value = newValue;
    return true;
} else {
    return false;
}

Portanto, o compareAndSetmétodo permitirá que você escreva um código que é garantido para executar apenas uma vez, mesmo quando chamado de vários threads. Por exemplo:

final AtomicBoolean isJobDone = new AtomicBoolean(false);

...

if (isJobDone.compareAndSet(false, true)) {
    listener.notifyJobDone();
}

É garantido que apenas notifique o ouvinte uma vez (assumindo que nenhum outro encadeamento AtomicBooleanretorne falsenovamente depois de ser definido como true).

Nam San
fonte
14

volatileA palavra-chave garante o relacionamento de antes do acontecimento entre os segmentos que compartilham essa variável. Não garante que 2 ou mais threads não se interrompam ao acessar essa variável booleana.

dhblah
fonte
14
O acesso booleano (como no tipo primitivo) é atômico em Java. Leituras e atribuições. Portanto, nenhum outro thread "interromperá" as operações booleanas.
Maciej Biłas
1
Sinto muito, mas como isso responde à pergunta? Uma Atomic*classe envolve um volatilecampo.
cinzento
Os caches da CPU não são o principal fator para definir voláteis? Para garantir que o valor lido seja, na verdade, o que foi definido mais recentemente
jocull 11/03/19
8

AtomicBoolean vs Volatile boolean

As classes Atomic * envolvem uma primitiva volátil do mesmo tipo. Da fonte:

public class AtomicLong extends Number implements java.io.Serializable {
   ...
   private volatile long value;
   ...
   public final long get() {
       return value;
   }
   ...
   public final void set(long newValue) {
       value = newValue;
   }

Portanto, se tudo o que você está fazendo é obter e configurar um Atomic *, é melhor ter apenas um campo volátil.

O que AtomicBoolean faz que um booleano volátil não pode alcançar?

Atômicas * aulas de dar-lhe métodos que fornecem funcionalidades mais avançadas, tais como incrementAndGet(), compareAndSet()e outros que implementam várias operações (get / incremento / set, teste / set), sem bloqueio. É por isso que as classes Atomic * são tão poderosas.

Por exemplo, se vários segmentos estiverem usando o seguinte código ++, haverá condições de corrida porque, ++na verdade, são: get, increment e set.

private volatile value;
...
// race conditions here
value++;

No entanto, o código a seguir funcionará em um ambiente multithread com segurança, sem bloqueios:

private final AtomicLong value = new AtomicLong();
...
value.incrementAndGet();

Também é importante observar que agrupar seu campo volátil usando a classe Atomic * é uma boa maneira de encapsular o recurso compartilhado crítico do ponto de vista de um objeto. Isso significa que os desenvolvedores não podem simplesmente lidar com o campo, supondo que ele não seja compartilhado, possivelmente injetando problemas com um campo ++; ou outro código que introduza condições de corrida.

cinzento
fonte
5

Se houver vários threads acessando a variável no nível da classe, cada thread poderá manter a cópia dessa variável em seu cache local do thread.

Tornar a variável volátil impedirá que os threads mantenham a cópia da variável no cache local do thread.

As variáveis ​​atômicas são diferentes e permitem a modificação atômica de seus valores.

Amol Gaikwad
fonte
4

O tipo primitivo booleano é atômico para operações de gravação e leitura, garante a volatilidade do princípio acontece antes. Portanto, se você precisar de um get () e um set () simples, não precisará do AtomicBoolean.

Por outro lado, se você precisar implementar alguma verificação antes de definir o valor de uma variável, por exemplo, "se verdadeiro, e depois definido como falso", será necessário executar essa operação também de maneira atômica, nesse caso, use compareAndSet e outros métodos fornecidos por AtomicBoolean, pois se você tentar implementar essa lógica com booleano volátil, precisará de alguma sincronização para garantir que o valor não seja alterado entre get e set.

user2660000
fonte
3

Lembre-se do IDIOM -

LER - MODIFICAR - ESCREVER isso que você não pode conseguir com materiais voláteis

MoveFast
fonte
2
Curto, crocante e direto ao ponto. volatilefunciona apenas nos casos em que o encadeamento do proprietário tem a capacidade de atualizar o valor do campo e os outros encadeamentos podem apenas ler.
Chaklader Asfak Arefe
3

Se você tiver apenas um thread modificando seu booleano, poderá usar um booleano volátil (normalmente você faz isso para definir uma stopvariável marcada no loop principal do thread).

No entanto, se você tiver vários threads modificando o booleano, use um AtomicBoolean. Senão, o seguinte código não é seguro:

boolean r = !myVolatileBoolean;

Esta operação é realizada em duas etapas:

  1. O valor booleano é lido.
  2. O valor booleano é gravado.

Se um outro encadeamento modificar o valor entre #1e 2#, você poderá obter um resultado errado. AtomicBooleanmétodos evitam esse problema executando etapas #1e #2atomicamente.

Thibaut D.
fonte
-1

Ambos têm o mesmo conceito, mas no booleano atômico, ele fornecerá atomicidade para a operação, caso o switch cpu ocorra no meio.

Bismaya Mohapatra
fonte