O que faz AtomicReference.compareAndSet uso () para determinação?
-
18-09-2019 - |
Pergunta
Digamos que você tenha a seguinte classe
public class AccessStatistics {
private final int noPages, noErrors;
public AccessStatistics(int noPages, int noErrors) {
this.noPages = noPages;
this.noErrors = noErrors;
}
public int getNoPages() { return noPages; }
public int getNoErrors() { return noErrors; }
}
e executar o seguinte código
private AtomicReference<AccessStatistics> stats =
new AtomicReference<AccessStatistics>(new AccessStatistics(0, 0));
public void incrementPageCount(boolean wasError) {
AccessStatistics prev, newValue;
do {
prev = stats.get();
int noPages = prev.getNoPages() + 1;
int noErrors = prev.getNoErrors;
if (wasError) {
noErrors++;
}
newValue = new AccessStatistics(noPages, noErrors);
} while (!stats.compareAndSet(prev, newValue));
}
No while (!stats.compareAndSet(prev, newValue))
última linha como é que o método compareAndSet
determinar a igualdade entre prev
e newValue
? É a classe AccessStatistics
necessário para implementar um método equals()
? Se não, por quê? O javadoc afirma o seguinte para AtomicReference.compareAndSet
atomicamente define o valor para o determinado valor atualizado se o valor atual == o valor esperado.
... mas esta afirmação parece muito geral e os tutoriais que eu li sobre AtomicReference não sugerem a implementação de um equals () para uma classe envolto em uma AtomicReference.
Se as classes envolvidas em AtomicReference são obrigados a implementar equals (), em seguida, para objetos mais complexos do que AccessStatistics
Eu estou pensando que pode ser mais rápido aos métodos sincronizar esse update do objeto e não usar AtomicReference.
Solução
Ele compara os refrerences exatamente como se você tivesse usado o operador ==. Isso significa que as referências devem estar apontando para a mesma instância. Object.equals () não é utilizado.
Outras dicas
Na verdade, ele faz não prev comparar e newValue!
Em vez disso, compara o valor armazenado dentro estatísticas para prev e somente quando aqueles são os mesmos, ele atualiza o valor armazenado dentro estatísticas para newValue. Como dito acima que utiliza o operador (==) para fazê-lo é igual. Isto significa que anly quando prev está apontando para o mesmo objeto que é armazenado nas estatísticas irá estatísticas ser atualizado.
Ele simplesmente verifica a igualdade de referência de objeto (aka ==), então se referência de objeto realizada por AtomicReference tinha mudado depois que você tem a referência, não vai alterar a referência, então você vai ter que começar de novo.
A seguir estão algumas do código-fonte de AtomicReference. AtomicReference refere-se a um objecto de referência. Esta referência é um membro variável volátil no exemplo AtomicReference como abaixo.
private volatile V value;
get () simplesmente retorna o último valor da variável (como voláteis fazer em um "acontece antes" forma).
public final V get()
A seguir é o método mais importante de AtomicReference.
public final boolean compareAndSet(V expect, V update) {
return unsafe.compareAndSwapObject(this, valueOffset, expect, update);
}
O compareAndSet (esperar, atualização) método chama o método compareAndSwapObject () da classe inseguro de Java. Esta chamada de método de invoca inseguras a chamada nativa, que invoca uma única instrução para o processador. "Espera" e "update" cada referência um objeto.
Se e somente se a variável "valor" membro de instância AtomicReference refere-se ao mesmo objeto é referido por "esperar", "update" é atribuído a essa variável de instância agora, e "verdadeiro" é retornado. Ou então, false é retornado. A coisa toda é feito atomicamente. Nenhum outro segmento pode interceptar no meio. Como se trata de uma única operação do processador (magia da arquitetura do computador moderno), é muitas vezes mais rápido do que usando um bloco sincronizado. Mas lembre-se que quando múltiplas variáveis ??precisam ser atualizados atomicamente, AtomicReference não vai ajudar.
Eu gostaria de adicionar um código de execução de pleno direito, que pode ser executado em eclipse. Ele iria limpar muitos confusão. Aqui 22 usuários (threads mito) está tentando reservar 20 lugares. A seguir está o fragmento de código seguido do código completo.
Código trecho onde 22 usuários estão tentando reservar 20 lugares.
for (int i = 0; i < 20; i++) {// 20 seats
seats.add(new AtomicReference<Integer>());
}
Thread[] ths = new Thread[22];// 22 users
for (int i = 0; i < ths.length; i++) {
ths[i] = new MyTh(seats, i);
ths[i].start();
}
A seguir está o link github para quem quer ver o código completo em execução que é pequeno e conciso. https://github.com/sankar4git/atomicReference/blob/master/Solution. java