Pergunta

Em Java, a atribuição é atômica se o tamanho da variável for menor ou igual a 32 bits, mas não o será se for maior que 32 bits.

O que (volátil/sincronizado) seria mais eficiente de usar em caso de atribuição dupla ou longa?

Como,

  volatile double x = y;

sincronizado não é aplicável com argumento primitivo.Como faço para usar sincronizado neste caso?Claro que não quero bloquear minha aula, então this não deve ser usado.

Foi útil?

Solução

Se você achar o bloqueio no próprio objeto muito pesado, o sincronizado é o caminho a percorrer. Antes do Java 1.5, o volátil pode ter sido uma boa escolha, mas agora o volátil pode ter um impacto muito grande, forçando a ordem das instruções no método em que a atribuição ocorre. Crie um objeto separado (private final Object X_LOCK = new Object();) e sincronize nele ao definir ou obter o valor desse duplo. Isso lhe dará um bom nível de controle sobre o bloqueio, o que parece que você precisa.

No novo pacote de simultaneidade, existem mais opções, como atomicreferência, que podem ser um bom substituto para o volátil se você realmente precisar evitar a sincronização.

Outras dicas

O que você está tentando fazer?O synchronized e volatile palavras-chave são mecanismos em Java que podem ser usados ​​para garantir que valores consistentes sejam observados por diferentes threads que leem os mesmos dados.Em particular, eles permitem que você raciocine sobre acontece antes relações em seus programas.

Você simplesmente não pode evitar o uso de um dos volatile ou synchronized para acessar adequadamente não-final campos em um programa multithread.Dito isto, o principal motivo pelo qual você provavelmente precisará synchronized sobre volatile é o requisito para usar atômico comparar e definir operações (ou seja, não será nenhuma consideração de desempenho).Por exemplo, em um programa multithread:

volatile int i = 0;

public void foo() { 
    if (i == 0) i = i + 1;
}

O código acima é inerentemente inseguro, embora a declaração da variável como volátil signifique que as leituras e gravações são liberadas para a memória principal - a única implementação segura de tal método seria algo como:

int i = 0;

public synchronized void foo() {
    if (i == 0) i = i + 1;
}

Então, qual você prefere?Bem, se você tiver vários threads modificando um campo dependendo do valor desse campo (ou seja,comparar e definir), então synchronized é a única solução segura.

Também vale a pena dizer: a sobrecarga de desempenho de synchronized Não é um problema (na esmagadora maioria dos casos).Os problemas de desempenho de sincronização geralmente são causados ​​por gargalos de código, deadlocks ou livelocks desnecessários e podem ser mitigados, se necessário.Qualquer ciclos de clock puros a sobrecarga será ofuscada por outras coisas que seu aplicativo faz:arquivo IO, consultas de banco de dados, comunicação remota etc.

Volátil é certamente o caminho a percorrer se você estiver apenas fazendo uma tarefa. Tenho certeza que você sabe, mas desde que foi criado: se você gostaria de fazer operações mais complexas (incremento o valor, por exemplo), precisaria sincronizar. I ++ nunca é seguro para qualquer tipo de variável. Você precisa sincronizar. I ++ e similares, já que isso é realmente mais de 1 operação.

Não: foi expresso que você poderia usar atomicdouble, mas atualmente não há atômico em java.util.concurrent.atomic

Se você estiver fazendo várias operações em x, isso exige defini -lo para um novo valor no final, é possível fazer isso de maneira segura de threads, sem travar o que nunca, e fazer com que seja seguro, usando comparar e definir. Exemplo:

AtomicLong x = new AtomicLong(SomeValue);
public void doStuff() {
  double oldX;
  double newX;
  do {
    oldX = x.get();
    newX = calculateNewX(oldX);
  } while (!x.compareAndSet
      (Double.doubleToLongBits(oldX), Double.doubleToLongBits(newX)));

Isso funciona porque a Comparansset verá se o valor de X mudou desde a última vez que você o lê. Se X mudou, você será forçado a fazer o cálculo novamente e a re-true a configuração.

É claro que você pode implementar sua própria atômica em vez de fazer essas conversões de DoubleTolongbits. Dê uma olhada no AtomicfieldUpdater.

KDSRATHORE, você pode usar alguns bloqueios explícitos ou fazer algum objeto fictício = new Object (), no qual você sincroniza no setter/getter desse duplo

De acordo com a documentação do Oracle, você pode usar o volátil para se referir ao objeto duplo:

volatile Double x = y;

"As gravações e as leituras das referências são sempre atômicas, independentemente de serem implementadas como valores de 32 ou 64 bits".

Licenciado em: CC-BY-SA com atribuição
Não afiliado a StackOverflow
scroll top