Faz este código resolver o dobro verificado fecho problema no Java?
-
12-11-2019 - |
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:
getInstance()
é não sincronizados, então, depois de INSTÂNCIA é inicializada não há nenhum custo para a sincronizaçãocreateInstance()
é sincronizado
Assim, a pergunta é:faz este código tem problemas?É legal e sempre thread-safe?
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.