Pergunta

Considerar o "double-check expressão para a inicialização lenta de campos de instância":

// Item 71 in Effective Java copied from esta entrevista com Bloch.
private volatile FieldType field;
FieldType getField() {
    FieldType result = field;
    if (result == null) { // First check (no locking)
        synchronized(this) {
            result = field;
            if (result == null) // Second check (with locking)
                field = result = computeFieldValue();
        }
    }
     return result;
}

Eu quero ser capaz de restaurar o campo de uma forma segura (forçá-lo a carregar novamente a partir do banco de dados, no meu caso).Eu suponho que nós poderíamos fazer isso por ter um método de reposição:

void reset() {
   field = null;
}

Esta é a forma padrão de fazer a reposição de campo?Será que é seguro?Qualquer armadilhas?Eu estou perguntando porque Bloch deu o seguinte aviso sobre verificou carregamento lento:"A expressão idiomática é muito rápido, mas também complicado e delicado, para não ser tentado modificá-lo de qualquer forma.Basta copiar e colar -- normalmente não é uma boa idéia, mas apropriada aqui."

Obrigado antecipadamente, Playa do Himalaia.

Foi útil?

Solução

Sim, esta é thread-safe.

O bloco sincronizado é evitar que vários segmentos de computeFieldValue() chamado desnecessariamente. Desde field é volátil, os acessos em reset e getField são todos bem-ordenada.

Se a primeira verificação é não nulo, getField é feito; result é retornado.

Caso contrário, um bloqueio é adquirido, excluindo qualquer outro segmento que pode definir o campo para não nulo, mas permitir a qualquer segmento para set field como nulo. Se qualquer thread faz field definido como nulo, nada deve ter mudado; essa é a condição que tem o fio para dentro do bloco sincronizado. Se outro segmento já havia adquirido o bloqueio após o check do segmento atual, e definir o campo para um valor não nulo, a segunda verificação irá detectar isso.

Outras dicas

Eu acho que isso deve ser seguro, mas só porque você está armazenando o campo em uma variável local. Depois de feito isso, não há nenhuma maneira para a referência de variável local para a mudança magicamente como nulo, mesmo se outro segmento está redefinindo valor a meio caminho do campo através.

Parece que isso vai funcionar, desde que o método de reposição é o método reset() listados acima. No entanto, se o método reset() instancia um novo objeto (como abaixo), você não poderia acabar potencialmente retornar algo diferente do que você pretende?

void reset() {
    field = new FieldType();
}

Eu acho que depende exatamente o que você quer dizer com thread-safe.

Você pode acabar com uma situação em que uma primeira instância é usado depois de um segundo. Isso pode ser aprovado, ou talvez não.

Eu acho reset() o método não é correta.Se você ler Item 71, você vai encontrar:

Este código pode parecer um pouco complicada.Em particular, a necessidade de que os variável resultado pode não ser claro.O que esta variável não é para garantir que o campo é somente leitura uma vez que no caso comum onde isso já inicializada.

A inicialização lenta não suponha que campo talvez alterado.Se o campo será definido como null entre estes operadores:

FieldType result = field;
if (result == null) { // First check (no locking)

getField() fornecer resultado incorreto.

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