Modo singleton do padrão de design java①
- Introdução ao modo singleton
- 8 categorias de padrões singleton
- Hungry Chinese (constante estática)
- Hungry Chinese (bloco de código estático)
- Preguiçoso (discussão insegura)
- Preguiçoso (thread safety, método de sincronização, baixa eficiência)
- Lazy (thread-safe, blocos de código sincronizados)
- Dupla verificação
- Classe interna estática
- enumerar
Funcionários e pequenos funcionários sempre têm problemas. Quanto mais alto quanto mais alto, mais alto é o preço, mais você não pode comparar; quanto mais dinheiro você não pode comparar, quanto mais você tem, melhor, é infinito; comer boa comida é tudo sobre comida, é bom estar contente, desista do carinho chega!
Aprendizagem de padrões de design, vou postar cerca de 23 padrões de design em um futuro próximo , fique atento ~
Introdução ao modo singleton
O chamado padrão de design singleton é usar um determinado método para garantir que em todo o sistema de software, só pode haver uma instância de objeto para uma determinada classe , e o objeto pode fornecer apenas um método de instância de objeto obtido.
8 categorias de padrões singleton
Negrito é recomendado
- Hungry Chinese (constante estática)
- Hungry Chinese (bloco de código estático)
- Preguiçoso (discussão insegura)
- Preguiçoso (thread safety, método de sincronização, baixa eficiência)
- Lazy (thread-safe, blocos de código sincronizados)
- Dupla verificação
- Classe interna estática
- enumerar
Hungry Chinese (constante estática)
public class InstanceMode01 {
//私有化构造器 外部不能 new
private InstanceMode01(){
}
//类的内部实现创建对象
private static final InstanceMode01 instance = new InstanceMode01();
//向外暴露一个静态方法
public static InstanceMode01 getInstance(){
return instance;
}
}
- Vantagens: o código é simples, a instanciação é concluída quando a classe é carregada e a sincronização de thread é evitada
- Desvantagens: como é criado quando a classe é carregada, o efeito de carregamento lento não é alcançado. Se a instância atual não for usada, pode causar perda de memória
Vamos ver se o singleton está implementado:
Avalie se o endereço de memória é o mesmo comparando hashCode () (a instância é a mesma):
InstanceMode01 instanceMode1 = InstanceMode01.getInstance();
InstanceMode01 instanceMode01 = InstanceMode01.getInstance();
Log.i("单利模式之饿汉静态方法01:",
instanceMode1.hashCode() + "\t" + instanceMode01.hashCode());
效果图(1.1)
:
Sugestão: pode ser usado, mas vai desperdiçar memória
Hungry Chinese (bloco de código estático)
public class InstanceMode02 {
//私有化构造器 外部不能 new
private InstanceMode02(){
}
//类的内部实现创建对象
private static final InstanceMode02 instance;
static {
//静态代码块创建单利
instance = new InstanceMode02();
}
//向外暴露一个静态方法
public static InstanceMode02 getInstance(){
return instance;
}
}
As vantagens e desvantagens são as mesmas do estilo chinês com fome (constante estática ), porque a classe interna estática será executada quando a classe for carregada e não há diferença do estilo chinês com fome (constante estática ), mas a escrita é diferente.
Compare hashCode:
效果图(1.2)
:
Sugestão: pode ser usado, mas vai desperdiçar memória
Preguiçoso (discussão insegura)
public class InstanceMode03 {
/**
* 私有化构造器 外部不能 new
*/
private InstanceMode03(){
}
private static InstanceMode03 instance;
//提供一个共有方法 使用到时才去创建intance
public static InstanceMode03 getInstance(){
if (instance == null) {
instance = new InstanceMode03();
}
return instance;
}
}
-
Vantagens: Desempenha um papel de carregamento lento, nenhum desperdício pode ser usado apenas em um único thread!
-
Desvantagens: thread não é seguro, multithreading não pode ser usado , quando em multithreading
假设有2条线程: 线程A走到if(instance == null) 线程B也走到 if(instance == null) 两个线程会同时走instance = new InstanceMode03(); 会创建2个实例,违背了单例模式的原则,所以在多线程的情况下不建议使用!
public static InstanceMode03 getInstance(){
if (instance == null) {
instance = new InstanceMode03();
}
return instance;
}
Compare hashCode:
效果图(1.3)
:
Não recomendado, multi-threading é uma obrigação no desenvolvimento de projetos!
Preguiçoso (thread safety, método de sincronização, baixa eficiência)
public class InstanceMode04 {
/**
* 私有化构造器 外部不能 new
*/
private InstanceMode04(){
}
private static InstanceMode04 instance;
//提供一个共有方法 使用到时才去创建intance
public static synchronized InstanceMode04 getInstance(){
if (instance == null) {
instance = new InstanceMode04();
}
return instance;
}
}
-
Vantagens: resolver problemas de segurança de thread
-
Desvantagens: eficiência muito baixa
假设我现在要执行100次getInstance() 那么这100次都要进行线程同步,而不是直接返回实例对象 我想要的结果是,如果现在已经存在实例,那么直接return给我实例对象即可 因为是线程同步,所以会排好队一个一个执行,效率低
Compare HashCode:
效果图(1.4)
:
Não recomendado: muito ineficiente
Lazy (thread-safe, blocos de código sincronizados)
public class InstanceMode05 {
/**
* 私有化构造器 外部不能 new
*/
private InstanceMode05(){
}
private static InstanceMode05 instance;
//提供一个共有方法 使用到时才去创建intance
public static InstanceMode05 getInstance(){
if (instance == null) {
synchronized (InstanceMode05.class){
instance = new InstanceMode05();
}
}
return instance;
}
}
Desvantagens: O
problema é o mesmo que a insegurança do thread preguiçoso de InstanceMode03 (). O
problema do threading não é resolvido, embora o bloco de código seja adicionado.
No caso de multi-threading, 2 instâncias serão criadas quando 2 getInstance () forem obtidos ao mesmo tempo.
Por que a adição de synchronized (InstanceMode05.class) () não resolve o problema de encadeamento?
public static InstanceMode05 getInstance(){
//1
if (instance == null) {
//2
synchronized (InstanceMode05.class){
//3
instance = new InstanceMode05(); //4
} //5
} //6
return instance;
}
Suposição:
Agora há thread A e thread B. Quando o thread A e o thread B são executados de forma síncrona, eles vão para a etapa 2 ao mesmo tempo, porque é síncrono, então se (instância == null) () pode ser executado, vá para o terceiro Ao passo, quando A foi primeiro, a instância foi criada, e agora B ainda está esperando do lado de fora, quando B passou a etapa após 3, 2 instâncias serão criadas, o que viola a ideia de singleton .
Compare HashCode:
效果图(1.5)
:
Não recomendado, o tópico não é seguro
Dupla verificação
public class InstanceMode06 {
/**
* 私有化构造器 外部不能 new
*/
private InstanceMode06() {
}
/**
* volatile:防止JVM优化被禁止重排序的。
* 重排序是指编译器和处理器为了优化程序性能而对指令序列进行重新排序的一种手段。
*/
private static volatile InstanceMode06 instance;
/*1*/
public static InstanceMode06 getInstance() {
/*2*/
if (instance == null) {
/*3*/
synchronized (InstanceMode06.class) {
/*4*/
if (instance == null) {
/*5*/
instance = new InstanceMode06();
}
}
}
return instance;
}
}
palavra-chave volátil:
volatile解决问题:
问题出在第5行:
在new创建变量的时候 instance = new InstanceMode06();
它并不是一个原子操作。事实上,它可以”抽象“为下面几条JVM指令:
memory = allocate(); // 1:分配对象的内存空间
ctorInstance(memory); // 2:初始化对象
instance = memory; // 3:设置instance指向刚分配的内存地址
操作2依赖于操作1,但是操作3并不依赖于操作2
所以JVM可以以“优化”为目的对它们进行重排序,经过重排序后如下:
memory = allocate(); // 1:分配对象的内存空间
instance = memory; // 3:设置instance指向刚分配的内存地址
// 注意,此时memory对象还没有被初始化!
ctorInstance(memory); // 2:初始化对象
这样做有什么区别呢?
正常情况是先分配对象的内存空间,然后初始化,最后instance指向分配的内存地址
现在有可能是先分配对象,然后直接指向内存地址,最后在初始化对象,
那么就有可能造成实例不同的情况
volatile关键字是防止JVM优化被禁止重排序,解决了重新排序的问题
O que são operações atômicas em java:
"A operação atômica não precisa ser sincronizada". A chamada operação atômica se refere a uma operação que não será interrompida pelo mecanismo de agendamento de thread; uma vez que esta operação for iniciada, ela será executada até o fim sem qualquer contexto entre eles. Switch ; da rede
Por que usar o bloqueio de verificação dupla?
当同步的情况下线程A和线程B同时到3时,因为是同步所以线程A先进去创建对象,
线程B在外面等待,当线程A结束后,线程B在进入,当线程B走到4时判断instance == null
此时实例已经创建,则不在重新创建实例
当再有新的线程创建的时候,此时实例已经创建完成,
走到2时,则直接返回当前实例,不进行线程同步
Verifique o código de referência do bloqueio:
public static InstanceMode06 getInstance() {
/*1*/
if (instance == null) {
/*2*/
synchronized (InstanceMode06.class) {
/*3*/
if (instance == null) {
/*4*/
instance = new InstanceMode06(); /*5*/
}
}
}
return instance;
}
Compare HashCode ():
效果图(1.6)
:
Recomendado para usar ☺
Classe interna estática
public class InstanceMode07 {
/**
* 私有化构造器 外部不能 new
*/
private InstanceMode07(){
}
private static InstanceMode07 instance;
//提供一个共有方法 使用到时才去创建intance
public static synchronized InstanceMode07 getInstance(){
return SingletonInstance.INSTANCE;
}
//静态内部类
public static class SingletonInstance{
private final static InstanceMode07 INSTANCE = new InstanceMode07();
}
}
vantagem:
- Ele não será criado diretamente quando a classe for carregada, garantindo que as
propriedades estáticas da classe carregada lentamente serão inicializadas apenas quando a classe for carregada.
Como a classe interna é usada, o thread não pode entrar quando a classe é inicializada, que garante a segurança do encadeamento (mecanismo JVM)
Compare HashCode:
效果图(1.7)
:
Uso recomendado
enumerar
public enum InstanceMode08 {
INSTANCE;
public int showEnum(){
return 10;
}
}
Com o modo singleton implementado por jdk1.5, não só os problemas de multithreading podem ser evitados, mas também problemas como desserialização e recriação de objetos podem ser evitados
Compare HashCode:
效果图(1.8)
:
<< Java eficaz >> autor josh Bloch defende o caminho
Nota:
Estou usando o projeto Android. Aqueles que nunca aprenderam Android podem baixar o código diretamente. Você pode baixar o projeto e você está executando ~
Artigos recentes:
O padrão de fábrica do padrão de design java (2)
Padrão de protótipo do padrão de design java (3)
O padrão construtor do padrão de design java (4)
Padrão de adaptador do padrão de design java (5)
Vá para a página do catálogo de padrões de design / princípios de design
É 2021/6. Em um futuro próximo, tentarei o meu melhor para atualizar todos os 23 padrões de design, portanto, fique atento ~
Originalidade não é fácil, seus gostos são o seu maior apoio para mim, por favor, gostem de me apoiar ~