Respostas:
Quando vários threads precisam verificar e alterar o booleano. Por exemplo:
if (!initialized) {
initialize();
initialized = true;
}
Isso não é seguro para threads. Você pode corrigi-lo usando AtomicBoolean
:
if (atomicInitialized.compareAndSet(false, true)) {
initialize();
}
true
quando initialize()
não foi concluído. Portanto, ele funciona apenas se outros threads não se importam com a conclusão de initialize()
.
initialized
estiver sendo simplesmente usado para garantir que um e apenas um thread invoque o initialize()
método. Obviamente, initialized
ser verdade não significa que a inicialização tenha sido concluída definitivamente neste caso; portanto, talvez um termo um pouco diferente seja melhor aqui. Mais uma vez, depende do que está sendo usado.
volatile boolean
seria o mesmo que AtomicBoolean
?
synchronized
bloco; nesse caso, você não precisa mais de um AtomicBoolean
, apenas um volatile boolean
. ( if(! this.initialized) { synchronized(this) { if(! this.initialized) { initialize(); this.initialized = true; } } }
Vai garantir que apenas um thread chama initialize
, e que todos os outros tópicos esperar por ele ter feito isso, desde que initialized
é marcado volatile
.)
Aqui estão as anotações (do livro de Brian Goetz ) que eu fiz, que podem ser úteis para você
Classes AtomicXXX
fornecer implementação de comparação e troca sem bloqueio
Aproveita o suporte fornecido pelo hardware (a instrução CMPXCHG na Intel) Quando muitos threads estão executando seu código que usa essa API de simultaneidade atômica, eles são dimensionados muito melhor do que o código que usa monitores / sincronização no nível de objeto. Como os mecanismos de sincronização do Java fazem a espera do código, quando há muitos threads em execução nas seções críticas, uma quantidade substancial de tempo da CPU é gasta no gerenciamento do próprio mecanismo de sincronização (espera, notificação, etc.). Como a nova API usa construções no nível de hardware (variáveis atômicas) e espera e bloqueia algoritmos para implementar a segurança de encadeamento, muito mais tempo da CPU é gasto "realizando coisas" em vez de gerenciar a sincronização.
além de oferecer melhor rendimento, eles também oferecem maior resistência a problemas de vivacidade, como impasse e inversão de prioridade.
Há duas razões principais pelas quais você pode usar um booleano atômico. Primeiro é mutável, você pode passá-lo como referência e alterar o valor associado ao próprio booleano, por exemplo.
public final class MyThreadSafeClass{
private AtomicBoolean myBoolean = new AtomicBoolean(false);
private SomeThreadSafeObject someObject = new SomeThreadSafeObject();
public boolean doSomething(){
someObject.doSomeWork(myBoolean);
return myBoolean.get(); //will return true
}
}
e na classe someObject
public final class SomeThreadSafeObject{
public void doSomeWork(AtomicBoolean b){
b.set(true);
}
}
Mais importante, porém, seu encadeamento é seguro e pode indicar aos desenvolvedores que mantêm a classe, que essa variável deve ser modificada e lida em vários encadeamentos. Se você não usar um AtomicBoolean, deverá sincronizar a variável booleana que estiver usando, declarando-a volátil ou sincronizada em torno da leitura e gravação do campo.
A AtomicBoolean
classe fornece um valor booleano que você pode atualizar atomicamente. Use-o quando você tiver vários threads acessando uma variável booleana.
A visão geral do pacote java.util.concurrent.atomic fornece uma boa descrição de alto nível do que as classes neste pacote fazem e quando usá-las. Eu também recomendaria o livro Java Concurrency in Practice, de Brian Goetz.
Trecho da descrição do pacote
Descrição do pacote java.util.concurrent.atomic: Um pequeno conjunto de ferramentas de classes que suportam a programação segura de threads sem bloqueio em variáveis únicas.
As especificações desses métodos permitem que as implementações empregem instruções atômicas eficientes no nível da máquina, disponíveis em processadores contemporâneos.
Instâncias das classes AtomicBoolean, AtomicInteger, AtomicLong e AtomicReference fornecem acesso e atualizações para uma única variável do tipo correspondente. [...]
Os efeitos de memória para acessos e atualizações de atômicas geralmente seguem as regras para voláteis:
- get tem os efeitos de memória de ler uma variável volátil.
- O conjunto possui os efeitos de memória da gravação (atribuição) de uma variável volátil.
- fracoCompareAndSet lê atomicamente e escreve condicionalmente uma variável, é ordenado com relação a outras operações de memória nessa variável, mas age como uma operação de memória não volátil comum.
- compareAndSet e todas as outras operações de leitura e atualização, como getAndIncrement, têm os efeitos de memória de leitura e gravação de variáveis voláteis.
volatile boolean
vsAtomicBoolean
: stackoverflow.com/questions/3786825/...