Pergunta

Faz este código resolver o dobro verificado fecho problema no Java?

public class DBAccessService() {
    private static DBAccessService INSTANCE;  

    private DBAccessService() {}

    public static DBAccessService getInstance() {
        if (INSTANCE != null) {
            return INSTANCE;
        }
        return createInstance();
    }

    private static synchronized DBAccessService createInstance() {
        if (INSTANCE != null) {
            return INSTANCE;
        }
        DBAccessService instance = new DBAccessService();
        INSTANCE = instance;

        return INSTANCE;
    }
}

Existem 2 aspectos para prestar atenção:

  1. getInstance() é não sincronizados, então, depois de INSTÂNCIA é inicializada não há nenhum custo para a sincronização
  2. createInstance() é sincronizado

Assim, a pergunta é:faz este código tem problemas?É legal e sempre thread-safe?

Foi útil?

Solução

Para resolver esta questão particular Java simultaneidade na prática (escrito por uma equipe que, basicamente, escreveu o java.util.simultâneas biblioteca) recomenda o A Inicialização lenta classe de titular idioma (página 348 na minha cópia, Listagem de 16.6, não 16.7)

@ThreadSafe
public class DBAccessServiceFactory {
  private static class ResourceHolder {
    public static DBAccessService INSTANCE = new DBAccessService();
  }
  public static DBAccessService getResource() {
    return ResourceHolder.INSTANCE;
  }
}

Este é sempre legal e Thread-safe.Eu não sou um especialista, então eu não posso dizer que este é melhor do que o seu código.No entanto, dado que é o padrão recomendado por Doug Lea e Joshua Bloch, eu sempre uso ele sobre o código que você ou eu inventei, como é tão fácil cometer erros (como demonstrado pelo número de respostas erradas para esta pergunta).

Relacionadas com o voláteis problema, eles dizem:

Alterações subsequentes no JMM (Java 5.0 e posterior) permitiram DCL para o trabalho, se o recurso é feita volátil ...No entanto, a inicialização lenta titular linguagem oferece os mesmos benefícios e é mais fácil de entender.

Outras dicas

Você precisa declarar INSTANCE como volatile para que ele funcione:

private static volatile DBAccessService INSTANCE;

Nota: ele só funciona com o Java 5 ou posterior.Ver O "Double-Checked Locking é Quebrado" Declaração.

Neste artigo alega-se que "double check log" não é um problema se você usar um separado classe Singleton:

public class DBAccessHelperSingleton {
    public static DBAccessHelper instance = new DBAccessHelper(); 
} 

Ele tem a mesma vantagem:O campo não é instanciado antes de ser referências primeira vez.

Como mencionado anteriormente, se você deseja manter como você tem volatile está em falta no caso de você são apenas direcionando o JDK >= 5.

Ele não é thread-safe, por favor, verifique uma excelente artigo.Não há nenhuma garantia de que um thread vai ver totalmente inicializado instância de DbAccessService.Por que não usando simples

public class DBAccessService() {
     public static DBAccessService INSTANCE = new DBAccessService();
}

Parece bem.Se duas threads chamar getInstance() e EXEMPLO não é initalized, apenas um thread vai ser capaz de prosseguir com o createInstance() e o segundo já vai ver que a instância não é nulo.

A única coisa é volatile palavra-chave, por EXEMPLO.Caso contrário, o java pode armazená-lo em cache.

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