Pesquisa de site

Segurança de encadeamento em classes Java Singleton


Singleton é um dos padrões de design criacional mais amplamente utilizado para restringir o objeto criado por aplicativos. Se você estiver usando em um ambiente multiencadeado, a segurança de encadeamento da classe singleton é muito importante. Em aplicativos do mundo real, recursos como conexões de banco de dados ou Enterprise Information Systems (EIS) são limitados e devem ser usados com sabedoria para evitar qualquer escassez de recursos. Para conseguir isso, podemos implementar uma classe wrapper para o recurso e limitar o número de objetos criados em tempo de execução a um.

Thread Safe Singleton em Java

  1. Crie o construtor privado para evitar a criação de qualquer novo objeto com o novo operador.
  2. Declare uma instância estática privada da mesma classe.
  3. Forneça um método estático público que retornará a variável de instância da classe singleton. Se a variável não for inicializada, inicialize-a ou simplesmente retorne a variável de instância.

Usando as etapas acima, criei uma classe singleton que se parece com a seguinte. ASingleton.java

package com.journaldev.designpatterns;

public class ASingleton {

	private static ASingleton instance = null;

	private ASingleton() {
	}

	public static ASingleton getInstance() {
		if (instance == null) {
			instance = new ASingleton();
		}
		return instance;
	}

}

No código acima, o método getInstance() não é thread-safe. Múltiplos threads podem acessá-lo ao mesmo tempo. Para os primeiros threads quando a variável de instância não é inicializada, vários threads podem entrar no loop if e criar várias instâncias. Isso interromperá nossa implementação de singleton.

Como obter segurança de thread na classe Singleton?

Existem três maneiras pelas quais podemos alcançar a segurança da rosca.

  1. Crie a variável de instância no momento do carregamento da classe. Prós:

  • Segurança de thread sem sincronização
  • Fácil de implementar

Contras:

  • Criação antecipada de recurso que pode não ser usado no aplicativo.
  • O aplicativo cliente não pode passar nenhum argumento, então não podemos reutilizá-lo. Por exemplo, ter uma classe singleton genérica para conexão de banco de dados onde o aplicativo cliente fornece propriedades de servidor de banco de dados.

  1. Sincronize o método getInstance(). Prós:

  • A segurança da linha é garantida.
  • O aplicativo cliente pode passar parâmetros
  • Inicialização lenta alcançada

Contras:

  • Desempenho lento devido à sobrecarga de bloqueio.
  • Sincronização desnecessária que não é necessária depois que a variável de instância é inicializada.

  1. Use bloco sincronizado dentro do loop if e variável volátil Prós:

  • A segurança do fio é garantida
  • O aplicativo cliente pode passar argumentos
  • Inicialização lenta alcançada
  • A sobrecarga de sincronização é mínima e aplicável apenas para os primeiros threads quando a variável é nula.

Contras:

  • Extra se condição

Olhando para todas as três maneiras de obter thread-safe, acho que a terceira é a melhor opção. Nesse caso, a classe modificada ficará assim:

package com.journaldev.designpatterns;

public class ASingleton {

	private static volatile ASingleton instance;
	private static Object mutex = new Object();

	private ASingleton() {
	}

	public static ASingleton getInstance() {
		ASingleton result = instance;
		if (result == null) {
			synchronized (mutex) {
				result = instance;
				if (result == null)
					instance = result = new ASingleton();
			}
		}
		return result;
	}

}

A variável local result parece desnecessária. Mas, está lá para melhorar o desempenho do nosso código. Nos casos em que a instância já está inicializada (na maioria das vezes), o campo volátil é acessado apenas uma vez (devido a \retornar resultado; ao invés de \retornar instância;). Isso pode melhorar o desempenho geral do método em até 25%. Se você acha que há maneiras melhores de conseguir isso ou se a segurança do thread está comprometida na implementação acima, comente e compartilhe com todos nós.

Dica bônus

segurança de encadeamento em java.

Você pode conferir mais exemplos de Java em nosso repositório GitHub.

Artigos relacionados: