padrão singleton
O chamado padrão de projeto singleton de uma classe é usar um determinado método para garantir que em todo o sistema de software, apenas uma instância de objeto possa existir para uma determinada classe, e a classe fornece apenas um método (método estático) para obter seu instância do objeto.
Como o SessionFactory do Hibernate, que atua como um proxy para a fonte de armazenamento de dados e é responsável por criar objetos Session. SessionFactory não é leve, em geral, um projeto normalmente só precisa de uma SessionFactory, que é o padrão singleton.
Existem oito maneiras de usar o padrão singleton:
- Estilo chinês com fome (constante estática)
- Estilo chinês faminto (bloco de código estático)
- Preguiçoso (thread inseguro)
- Lazy (métodos seguros para threads e sincronizados)
- Lazy (blocos de código sincronizados e seguros para threads)
- dupla verificação
- classe interna estática
- enumerar
Chinês faminto
1.
Exemplo de aplicação de constante estática em chinês com fome (constante estática) As
etapas são as seguintes:
- Privatização do construtor (para evitar acesso externo ao construtor dentro da classe, ou seja, você não pode usar a palavra-chave new para criar objetos)
- Objetos criados dentro da classe
- Exponha um método público estático. getInstance
- Código
exemplo:
/**
* @author 小关同学
* @create 2021/9/13
*/
//饿汉式(使用静态变量实现)
class SingleTon{
//1、构造器私有化,对外不提供new
private SingleTon(){
}
//2、本类内部创建对象实例
private final static SingleTon instance = new SingleTon();
//3、提供一个公有的静态方法,返回实例对象
public static SingleTon getInstance(){
return instance;
}
}
public class Type1 {
public static void main(String[] args) {
SingleTon instance = SingleTon.getInstance();
SingleTon instance2 = SingleTon.getInstance();
System.out.println(instance == instance2);//结果是true,证明两个对象相等
}
}
Análise das vantagens e desvantagens
Vantagens: Este método de escrita é relativamente simples, ou seja, a instanciação é concluída quando a classe é carregada. Evita problemas de sincronização de threads .
Desvantagens: A instanciação é concluída quando a classe é carregada, o que não atinge o efeito de Lazy Loading . Se a instância nunca for usada do início ao fim, causará um desperdício de memória.
Este método evita o problema de sincronização de várias threads com base no mecanismo ClassLoder. No entanto, a instância é instanciada quando a classe é carregada. No modo singleton, a maioria delas chama o método getInstance. No entanto, existem muitos motivos para o carregamento da classe, portanto é impossível Certificar-se de que existem outras maneiras (ou outros métodos estáticos) de causar carregamento de classe.Neste momento, inicializar a instância não obterá o efeito de carregamento lento.
Conclusão: Este padrão singleton está disponível e pode causar desperdício de memória
2. Exemplo de bloco de código estático :
//饿汉式(使用静态代码块实现)
class SingleTon{
private SingleTon(){
}
private static SingleTon instance;
//在静态代码块中创建单例对象
static {
instance = new SingleTon();
}
public static SingleTon getInstance(){
return instance;
}
}
Análise de vantagens e desvantagens
Este método é semelhante ao método acima, exceto que o processo de instanciação da classe é colocado no bloco de código estático. Quando a classe é carregada, o código no bloco de código estático é executado para inicializar a instância do aula. Os prós e contras são os mesmos acima.
Conclusão: Este padrão singleton está disponível, mas pode causar desperdício de memória
preguiçoso
1. Exemplo de gravação insegura para thread :
/**
* @author 小关同学
* @create 2021/9/13
*/
//懒汉式(线程不安全)
class SingleTon{
private static SingleTon instance;
private SingleTon(){
}
//提供一个静态的公有方法,当使用到该方法时,才去创建instance
//即懒汉式
public static SingleTon getInstance(){
if (instance==null){
instance = new SingleTon();
}
return instance;
}
}
public class Type2 {
public static void main(String[] args) {
SingleTon instance = SingleTon.getInstance();
SingleTon instance2 = SingleTon.getInstance();
System.out.println(instance == instance2);
}
}
Análise de vantagens e desvantagens
Vantagens: Jogou o efeito de Lazy Loading.
Desvantagem: Ele só pode ser usado em um único thread . Se um thread entrar no bloco de instrução de julgamento if (singleton == null) em multi-threading, ele não terá tempo para executá-lo, e outro thread também passará por esse comando de julgamento. Neste momento, várias instâncias serão geradas.
Conclusão: No desenvolvimento real, não use este método
2. Métodos sincronizados e seguros para thread
Exemplo:
//懒汉式(线程安全,同步方法)
class SingleTon{
private static SingleTon instance;
private SingleTon(){
}
//加入了同步方法,解决了线程不安全的问题
public static synchronized SingleTon getInstance(){
if (instance == null){
instance = new SingleTon();
}
return instance;
}
}
public class Type2 {
public static void main(String[] args) {
SingleTon instance = SingleTon.getInstance();
SingleTon instance2 = SingleTon.getInstance();
System.out.println(instance == instance2);
}
}
Análise de vantagens e desvantagens
Vantagens: resolve o problema de insegurança de thread
Desvantagens: A eficiência é muito baixa, quando cada thread deseja obter uma instância da classe, precisa sincronizar a execução do método getInstance(). Na verdade, este método é suficiente para executar o código de instanciação apenas uma vez, se você quiser obter uma instância dessa classe posteriormente, basta retorná-la diretamente. O método é muito ineficiente para sincronização
Conclusão: No desenvolvimento real, este método não é recomendado.
3. Encadeie blocos de código inseguros e sincronizados
Exemplo:
//懒汉式(线程不安全,同步代码块)
class SingleTon{
private static SingleTon instance;
private SingleTon(){
}
public static SingleTon getInstance(){
if (instance == null){
//同步代码块
synchronized (SingleTon.class){
instance = new SingleTon();
}
}
return instance;
}
}
public class Type2 {
public static void main(String[] args) {
SingleTon instance = SingleTon.getInstance();
SingleTon instance2 = SingleTon.getInstance();
System.out.println(instance == instance2);
}
}
Análise das vantagens e desvantagens
Este método visa melhorar o quarto método de implementação, pois a eficiência do método de sincronização anterior é muito baixa e é alterado para sincronizar para gerar blocos de código instanciados.
Mas essa sincronização não desempenha o papel de sincronização de threads! ! ! Consistente com a situação encontrada no terceiro método de implementação, se um thread entrar no bloco de julgamento if (singleton == null) e ainda não tiver tido tempo de executá-lo, outro thread também passará na instrução de julgamento, então ele gerará várias instâncias
Conclusão: No desenvolvimento real, este método não pode ser utilizado.
dupla verificação
exemplo:
/**
* @author 小关同学
* @create 2021/9/13
*/
//双重检查(线程安全,线程同步)
class SingleTon{
//volatile使instance变量的状态在各个线程之间是可见的
private static volatile SingleTon instance;
private SingleTon(){
}
//解决线程安全的问题,同时解决懒加载的问题,同时解决懒加载问题
public static SingleTon getInstance(){
if (instance == null){
//同步代码块
synchronized (SingleTon.class){
if (instance == null){
instance = new SingleTon();
}
}
}
return instance;
}
}
public class Type3 {
public static void main(String[] args) {
SingleTon instance = SingleTon.getInstance();
SingleTon instance2 = SingleTon.getInstance();
System.out.println(instance == instance2);
}
}
De acordo com a análise de código acima, se três encadeamentos a, b e c entrarem no método getInstance(), os encadeamentos a e b inserem a primeira instrução de julgamento if (instance == null) juntos, e o encadeamento a é mais avançado que o encadeamento b . Insira primeiro o bloco de código de sincronização. Neste momento, como apenas um thread tem permissão para executar no bloco de código de sincronização, o thread a primeiro inicializa a instância e, em seguida, sai do bloco de código de sincronização; neste momento, como o thread a sai do bloco de código de sincronização, então a thread b pode entrar no bloco de código de sincronização. Após a thread b entrar no bloco de código de sincronização, uma vez que a thread a já inicializou a instância, a thread b não inicializará a instância novamente e sairá diretamente o bloco de código de sincronização; Foi inicializado, portanto, não entrou na instrução de julgamento.
Análise de vantagens e desvantagens
Vantagens: segurança de rosca, carregamento lento, alta eficiência
O conceito de Double-Check é frequentemente usado no desenvolvimento multi-thread.Como mostrado no código acima, realizamos duas verificações if (singleton == null) para garantir a segurança do thread.
Dessa forma, o código de instanciação precisa ser executado apenas uma vez, e quando for acessado novamente posteriormente, julgue se (singleton == null), retorne diretamente o objeto instanciado e evite a repetição de sincronização de métodos.
Conclusão: No desenvolvimento real, este padrão de projeto singleton é recomendado.
classe interna estática
exemplo:
/**
* @author 小关同学
* @create 2021/9/13
*/
//静态内部类实现
class SingleTon{
private static SingleTon instance;
private SingleTon(){
}
//写一个静态内部类,该类中有一个静态属性
private static class SingleTonInstance{
private static final SingleTon INSTANCE = new SingleTon();
}
//提供一个公有方法,直接返回SingleTonInstance.INSTANCE
public static SingleTon getInstance(){
return SingleTonInstance.INSTANCE;
}
}
public class Type4 {
public static void main(String[] args) {
SingleTon instance = SingleTon.getInstance();
SingleTon instance2 = SingleTon.getInstance();
System.out.println(instance == instance2);
}
}
Análise de código, escrevemos uma classe interna estática SingleTonInstance em SingleTon, SingleTonInstance não será carregado imediatamente quando a classe SingleTon for carregada, e a classe SingleTonInstance não será carregada até que a propriedade estática INSTANCE na classe SingleTonInstance seja chamada no método getInstance(). é carregado para obter o efeito de carregamento lento e o processo de carregamento de classe JVM é seguro para threads.
Análise das vantagens e desvantagens
Esse método adota o mecanismo de carregamento de classes para garantir que haja apenas uma thread quando a instância for inicializada.
O método da classe interna estática não será instanciado imediatamente quando a classe Singleton for carregada, mas quando for necessário instanciar, o método getInstance será chamado e a classe SingletonInstance será carregada, completando assim a instanciação do Singleton.
As propriedades estáticas de uma classe são inicializadas apenas quando a classe é carregada pela primeira vez, então aqui, a JVM nos ajuda a garantir a segurança do encadeamento.Quando a classe é inicializada, outros encadeamentos não podem entrar.
Vantagens: evite a insegurança de thread, use recursos de classe interna estática para obter carregamento atrasado, alta eficiência
Conclusão: Recomendado para uso.
enumerar
exemplo:
/**
* @author 小关同学
* @create 2021/9/13
*/
//枚举(使用枚举也可以实现单例)
enum SingleTon{
INSTANCE; //属性
public void sayOK(){
System.out.println("ok~");
}
}
public class Type5 {
public static void main(String[] args) {
SingleTon instance = SingleTon.INSTANCE;
SingleTon instance2 = SingleTon.INSTANCE;
System.out.println(instance == instance2);
}
}
Análise de vantagens e desvantagens
Isso implementa o padrão singleton com a ajuda da enumeração adicionada no JDK1.5. Não apenas evita problemas de sincronização multi-thread, mas também evita que a desserialização recrie novos objetos .
Essa abordagem é defendida pelo autor do Effective Java, Josh Bloch
Conclusão: Recomendado para uso
Aplicação do padrão singleton no JDK
No JDK, java.lang.Runtime é o modo singleton clássico (estilo chinês faminto). Vamos dar uma olhada em seu código-fonte, conforme mostrado abaixo:
Resumir
- O modo singleton garante que apenas um objeto dessa classe exista na memória do sistema, economizando recursos do sistema. Para alguns objetos que precisam ser criados e destruídos com frequência, o uso do modo singleton pode melhorar o desempenho do sistema
- Quando você deseja instanciar uma classe singleton, você deve se lembrar de usar o método correspondente para obter o objeto, não o novo
- Cenários usados pelo padrão singleton: objetos que precisam ser criados e destruídos com frequência, demoram ou consomem recursos para criar objetos (ou seja: objetos pesados), mas objetos usados com frequência, objetos de ferramentas, objetos frequentes Objetos que acessam bancos de dados ou arquivos (como fontes de dados, fábricas de sessão, etc.)
PS: Você também pode ir ao meu blog pessoal para ver mais conteúdo
Endereço do blog pessoal: blog do colega de classe Xiaoguan