Inicialização Eager
O padrão eager initialization (inicialização anteicpada) cria a instância no momento do carregamento da classe. Esta abordgaem garante segurança em ambientes multithreaded, porém pode consumir recursos desnecessários caso o objeto nunca seja utilizado.
class ConfiguradorGlobal {
private static final ConfiguradorGlobal instancia = new ConfiguradorGlobal();
private ConfiguradorGlobal() {
}
public static ConfiguradorGlobal obterInstancia() {
return instancia;
}
}
Quando utilizar:
- Quando o objeto representa um recurso compartilhado entre múltiplos módulos
- Como ponto de acesso global (como gerenciadores de configuração ou logging)
- Quando há alta confiança de que a instância será utilizada
- Quando o custo de criação do objeto é baixo
Inicialização Lazy (Não Thread-Safe)
A implementação lazy initialization (inicialização preguiçosa) posterga a criação da instância até o primeiro acesso. Embora economize recursos, esta versão não é segura para aplicações multithreaded.
class GerenciadorRecursos {
private static GerenciadorRecursos referencia;
private GerenciadorRecursos() {
}
public static GerenciadorRecursos obterInstancia() {
if (referencia == null) {
referencia = new GerenciadorRecursos();
}
return referencia;
}
}
Inicialização Lazy (Com Sincronização)
Para resolver o problema de concorrência, podemos adicionar synchronization ao método. Esta solução é thread-safe, porém impacta o desempenho devido ao lock em todas as chamadas.
class ServicoCompartilhado {
private static ServicoCompartilhado instancia;
private ServicoCompartilhado() {
}
public static synchronized ServicoCompartilhado obterInstancia() {
if (instancia == null) {
instancia = new ServicoCompartilhado();
}
return instancia;
}
}
Double-Checked Locking
A técnica double-checked locking otimiza o desempenho verificando a condição antes e depois do bloco sincronizado, reduzindo a contenção de locks.
class NucleoAplicacao {
private static volatile NucleoAplicacao contexto;
private NucleoAplicacao() {
}
public static NucleoAplicacao obterInstancia() {
if (contexto == null) {
synchronized (NucleoAplicacao.class) {
if (contexto == null) {
contexto = new NucleoAplicacao();
}
}
}
return contexto;
}
}
Static Inner Class (Recomendado)
Esta abordagem utiliza classes internas estáticas para obter lazy loading天然 com segurença thread-safe, sem necessidade de sincronização explícita.
class FabricaServicos {
private FabricaServicos() {
}
private static class Holder {
private static final FabricaServicos instancia = new FabricaServicos();
}
public static FabricaServicos obterInstancia() {
return Holder.instancia;
}
}
Comparativo das Abordagens
| Abordagem | Thread-Safe | Lazy Loading | Desempenho |
|---|---|---|---|
| Eager Initialization | Sim | Não | Excelente |
| Lazy (Não sincronizado) | Não | Sim | Excelente |
| Lazy (Sincronizado) | Sim | Sim | Regular |
| Double-Checked Locking | Sim | Sim | Bom |
| Static Inner Class | Sim | Sim | Excelente |
Recomendações de Uso
Para aplicações que necessitam de lazy loading com alta performance em ambiente multithreaded, a abordagem static inner class é amplamente recomendada por sua simplicidade e eficiência. O double-checked locking permanece como excelente opção quando a implementação via classe interna não é viável.
A escolha entre eager e lazy initialization deve considerar o custo de criação do objeto e a probabilidade de utilização efetiva da instância durante o ciclo de vida da aplicação.