Design Java singleton

Exija um:

    Certifique-se de que haja apenas uma instância da classe em uma JVM (compartilhamento multi-thread)

solução

  1) Certifique-se de que o mundo externo da classe não deve construir diretamente o objeto
  2) Colocar a instância da classe no pool? (Pool de inteiros, pool de strings, ...)

Plano de pouso:

Solução 1: criar objetos de instância quando a classe é carregada, cenários de aplicação: objetos pequenos (menor uso de memória)

---> Estilo chinês Hungry (thread safety, alta eficiência de chamada, mas sem atraso de carregamento):

class Singleton01{
	//private byte[]array=new byte[1024*1024];
	//1.构建方法私有化
	private Singleton01() {}
	//2.类的内部构建对象
	private static  Singleton01 instance=new Singleton01();
	//3.对外提供对象访问
	public static Singleton01 getInstance() {
		return instance;
	}
	public static void show() {}
	public void display() {}
}

Pensando: Se o método show for chamado muitas vezes, e o método display for chamado no final ou raramente, isso causará a criação do objeto Singleton01 no início. Se o objeto for grande, isso causará um desperdício de recursos.

Solução 2: Quando e quando criar uma instância da classe , cenário de aplicação: objetos grandes (ocupam mais memória), raramente usados;

---> Estilo lento (thread safety, baixa eficiência de chamada, mas pode ser carregado com atraso):

class Singleton02{
	//private byte[]array=new byte[1024*1024];
	//1.构建方法私有化
	private Singleton02() {}
	//2.类的内部构建对象
	private static  Singleton02 instance;
	//3.对外提供对象访问(会有阻塞)
	public synchronized static Singleton02 getInstance() {
		if(instance==null) {
			System.out.println("create()");
			instance=new Singleton02();
		}
		return instance;
	}
	public static void show() {}
	public void display() {}
}

Pensando: No caso de multithreading, bloqueios são necessários. Se o código a seguir não estiver bloqueado, o objeto será construído duas vezes. Multithreading com bloqueios bloqueará

	static void doMethod02() {
		Thread t1=new Thread() {
		   @Override
		   public void run() {
			  Singleton02.getInstance();
			  Singleton02.getInstance();
		   }	
		};
		Thread t2=new Thread() {
			@Override
			public void run() {
				Singleton02.getInstance();
				Singleton02.getInstance();
			}	
		};
		t1.start();
		t2.start();
	}

	public static void main(String[] args) {
		doMethod02();
	}

Resultado de saída:

create()
create()

Opção 3: Reduzir o bloqueio com base na Opção 2, a verificação dupla reduz muito o bloqueio

---> Double CheckLock realiza um único caso: DCL é o mecanismo de julgamento de bloqueio duplo ( devido ao modelo JVM subjacente, podem ocorrer problemas ocasionais, portanto, não é recomendado ):

O papel da palavra-chave volatile?
    1) Garanta a visibilidade das variáveis ​​entre vários threads (um thread modifica o valor desta variável e os outros são imediatamente visíveis)

               -------- Artigo de referência: https://blog.csdn.net/qianzhitu/article/details/103052040

   2) A reordenação de instruções é proibida (a JVM otimizou a execução de instruções)

class Singleton03{//应用场景:大对象(占用内存比较多),稀少用
	//private byte[]array=new byte[1024*1024];
	//1.构建方法私有化
	private Singleton03() {}
	//2.类的内部构建对象
	private static volatile Singleton03 instance;
	//3.对外提供对象访问(会有阻塞)
	//3.1多个线程并发访问此方法是否会有线程不会被阻塞?(有的)
	//3.2为什么synchronized内部还要有一次判断?(确保对象只创建1次)
	public static Singleton03 getInstance() {
		if(instance==null) {
			synchronized(Singleton03.class) {
				System.out.println("synchronized");
				if(instance==null) {
					//System.out.println("create()");
					instance=new Singleton03();
					//对象创建过程(开辟内存,初始化属性,调用构造方法,为instance赋值)
				}
			}
		}
		return instance;
	}
}

Solução 4: implemente o carregamento lento de objetos com base em classes internas. Com base na solução 3, continue a reduzir o congestionamento enquanto otimiza o uso de recursos. Cenários de aplicativos: objetos grandes (carregamento lento), usados ​​com frequência

---> Modo de implementação de classe interna estática (segurança de thread, alta eficiência de chamada, carregamento de atraso)

          Nota: Apenas variáveis ​​estáticas podem ser escritas em classes internas estáticas, e variáveis ​​estáticas não podem ser escritas em classes internas não estáticas (a sintaxe é assim)

class Singleton04{
	//private byte[] array=new byte[1024*1024];
	private Singleton04() {}
	//Singleton04加载时不会加载Inner类
	private static class Inner{
		private static final Singleton04 instance=new Singleton04();
	}
	//可以频繁访问(没有阻塞)
	public static Singleton04 getInstance() {
		//基于内部类实现对象的延迟加载
		return Inner.instance;
	}
	//public static void show() {}
	//public void display() {}
}

Pensando: quando o método show é chamado, ele não fará com que a variável do array seja inicializada, nem carregue a classe Inner; quando a instância é obtida chamando o método getInstance, chamar Inner.instance fará com que a classe interna estática Inner seja carregada, inicialize a instância e execute new Singleton04 (), faz com que o array seja inicializado e realiza o carregamento lento de objetos grandes.

Esquema 5: Com base na enumeração; cenário de aplicação: pequenos objetos, usados ​​com frequência

---> Classe de enumeração (segurança de thread, alta eficiência de chamada, não pode ser carregado com atraso, pode impedir naturalmente chamadas de reflexão e desserialização)

enum Singleton05{//Singleton05.class
	INSTANCE;//此对象可以延迟加载吗?不可以
	//private byte[] array=new byte[1024*1024];
	public static void show() {}
}

transferir:

	static void doMethod05() {
		Singleton05.INSTANCE.show();
	}

Pensando: O objeto é construído quando a classe de objeto de enumeração é carregada e o carregamento lento não pode ser feito. Se for uma grande matriz de objetos, ocupará recursos quando a classe for carregada, o que não é adequado; portanto, só é adequado para objetos pequenos e cenários usados ​​com frequência;

Como escolher:

- Objetos singleton ocupam menos recursos, não precisam atrasar o carregamento, a enumeração é melhor do que fome

-Os objetos singleton ocupam muitos recursos e precisam ser carregados com um atraso. As classes internas estáticas são melhores do que as preguiçosas

 

 

Exigir dois:

        Certifique-se de que haja apenas uma instância da classe em um encadeamento (singleton encadeado)

 Afirmação:

        1) Este tipo de instância tem apenas uma cópia por thread (um singleton dentro do thread)
        2) Este objeto não pode ser construído fora

Destino da solução: baseado na implementação ThreadLocal

package com.java.design;

class Looper{//迭代器(任意的一个对象)
	private Looper() {
		System.out.println("Looper()");
	}
	private static ThreadLocal<Looper> td=new ThreadLocal<>() ;
	public static Looper getLooper() {
		//1.从当前线程获取looper对象
		Looper looper=td.get();//key是谁?
		//2.当前线程没有则创建looper并绑定到当前线程
		if(looper==null) {
			looper=new Looper();
			td.set(looper);//key是谁?ThreadLocal
		}
		//3.返回looper实例
		return looper;
	}
}
public class TestSingleton02 {
	public static void main(String[] args) {
		for(int i=0;i<3;i++) {
			new Thread() {
				@Override
				public void run() {
					Looper.getLooper();
					Looper.getLooper();
					Looper.getLooper();
				}
			}.start();
		}
	}
}

Resultado de saída:

Looper()
Looper()
Looper()

 

  

 

Acho que você gosta

Origin blog.csdn.net/qianzhitu/article/details/103047262
Recomendado
Clasificación