Referência volátil do Java vs. AtomicReference


135

Existe alguma diferença entre uma volatilereferência de objeto e AtomicReferenceno caso de eu apenas usar get()e set()-methods AtomicReference?

Respostas:


114

A resposta curta é: Não.

Na java.util.concurrent.atomicdocumentação do pacote. Citar:

Os efeitos de memória para acessos e atualizações de atômicas geralmente seguem as regras para voláteis:

  • gettem os efeitos de memória da leitura de uma volatilevariável.
  • settem os efeitos de memória de escrever (atribuir) uma volatilevariável.

A propósito, essa documentação é muito boa e tudo é explicado.


AtomicReference::lazySeté uma operação mais recente (Java 6+) introduzida que possui semântica inatingível por meio de volatilevariáveis. Veja este post para mais informações.


11
E a resposta mais longa seria?
Julien Grenier

Acordado. Pelo menos precisamos de um link.
Julien Chastang


42

Não, não há.

A energia adicional fornecida pelo AtomicReference é o método compareAndSet () e os amigos. Se você não precisar desses métodos, uma referência volátil fornecerá a mesma semântica que AtomicReference.set () e .get ().


14

Existem várias diferenças e trocas:

  1. O uso de um AtomicReferenceget / set tem a mesma semântica JMM que um campo volátil (como o javadoc afirma), mas AtomicReferenceé um invólucro em torno de uma referência, portanto, qualquer acesso ao campo envolve uma busca adicional por ponteiro .

  2. O espaço ocupado pela memória é multiplicado (assumindo um ambiente de OOPs compactado, o que é verdadeiro para a maioria das VMs):

    • ref volátil = 4b
    • AtomicReference = 4b + 16b (cabeçalho do objeto 12b + campo de ref 4b)
  3. AtomicReferenceoferece uma API mais rica que uma referência volátil. Você pode recuperar a API para a referência volátil usando um AtomicFieldUpdater, ou com Java 9 a VarHandle. Você também pode alcançar diretamente sun.misc.Unsafese gosta de correr com uma tesoura. AtomicReferenceem si é implementado usando Unsafe.

Então, quando é bom escolher um sobre o outro:

  • Precisa apenas de obter / definir? Fique com um campo volátil, a solução mais simples e a menor sobrecarga.
  • Precisa da funcionalidade extra? Se essa é uma parte sensível ao desempenho (sobrecarga de velocidade / memória) do seu código, escolha entre AtomicReference/ AtomicFieldUpdater/ Unsafeonde você tende a pagar em legibilidade e risco pelo ganho de desempenho. Se esta não é uma área sensível, basta procurar AtomicReference. Os criadores de bibliotecas geralmente usam uma combinação desses métodos, dependendo dos JDKs direcionados, das restrições esperadas da API, das restrições de memória e assim por diante.

7

O código fonte do JDK é uma das melhores maneiras de responder a confusões como essa. Se você observar o código no AtomicReference, ele usará uma variável volatie para armazenamento de objetos.

private volatile V value;

Então, obviamente, se você vai usar apenas get () e set () no AtomicReference, é como usar uma variável volátil. Mas, como outros leitores comentaram, o AtomicReference fornece semântica adicional do CAS. Portanto, primeiro decida se deseja ou não a semântica do CAS e, se desejar, use o AtomicReference.


13
"O código fonte do JDK é uma das melhores maneiras de responder a confusões como esta" => Não concordo necessariamente - o javadoc (que é o contrato da classe) é o melhor caminho. O que você encontra no código responde à pergunta para uma implementação específica, mas o código pode mudar.
assylias 03/02

4
Por exemplo, essa variável no hashmap era volátil no JDK 6, mas não é mais volátil no Java 7. Se você baseou seu código no fato de que a variável era volátil, ela seria quebrada ao atualizar o JDK ... É certo que o exemplo é diferente, mas você entende.
assylias

Esse CAS é alguma abreviação padrão?
abbas

1
Compare e troque =)
infinito

4

AtomicReferencefornece funcionalidade adicional que uma variável volátil simples não fornece. Ao ler a Javadoc da API, você saberá disso, mas também fornece um bloqueio que pode ser útil para algumas operações.

No entanto, a menos que você precise dessa funcionalidade adicional, sugiro que você use um volatilecampo simples .


Portanto, a diferença está no desempenho deles. Se não houvesse diferença, você nunca sugeriria usar um sobre o outro.
BT

O desempenho é praticamente o mesmo. Um AtomicRefrence adiciona complexidade e uso de memória.
Peter Lawrey

A @BT volatilecampo pode ser usado como qualquer campo regular, enquanto acessar o valor em uma AtomicReferencerequer passando gete setmétodos.
David Harkness

0

Às vezes, mesmo se você usar apenas get e sets, AtomicReference pode ser uma boa opção:

Exemplo com volátil:

private volatile Status status;
...
public setNewStatus(Status newStatus){
  status = newStatus;
}

public void doSomethingConditionally() {
  if(status.isOk()){
    System.out.println("Status is ok: " + status); // here status might not be OK anymore because in the meantime some called setNewStatus(). setNewStatus should be synchronized
  }
}

A implementação com o AtomicReference forneceria uma sincronização de cópia na gravação gratuitamente.

private AtomicReference<Status> statusWrapper;
...

public void doSomethingConditionally() {
  Status status = statusWrapper.get();
  if(status.isOk()){
    System.out.println("Status is ok: " + status); // here even if in the meantime some called setNewStatus() we're still referring to the old one
  }
}

Pode-se dizer que você ainda poderia ter uma cópia adequada se substituísse:

Status status = statusWrapper.get();

com:

Status statusCopy = status;

No entanto, é mais provável que o segundo seja removido por alguém acidentalmente no futuro durante a "limpeza de código".

Ao utilizar nosso site, você reconhece que leu e compreendeu nossa Política de Cookies e nossa Política de Privacidade.
Licensed under cc by-sa 3.0 with attribution required.