bloqueio java e verificação dupla

Verifique o bloqueio / verifique o bloqueio O julgamento anti-aéreo de camada dupla tem sido problemático por um longo tempo. Instância

public class Singleton {
    private volatile static Singleton singleton;

  //私有构造函数避免调用
    private Singleton (){}
    public static Singleton getSingleton() {

    // 先判断对象是否创建过
        if (singleton == null) {

        //类对象加锁
            synchronized (Singleton.class) {
                if (singleton == null) {
                    singleton = new Singleton();
                    //字节码层
                    //JIT CPU 可能对如下指令进行重排序
                    // 1.分配空间
                    // 2.初始化
                    // 3.引用赋值
                    如果指令重排后指令如下:
                    //1.分配空间
                    //3.引用赋值 如果在当前指令执行完后,有其他线程获取到实例,将拿到未初始化的实例;
                    //2. 初始化
                }
            }
        }
        return singleton;
    }
}


Explicação: Quando A e B chamam getSingleton ao mesmo tempo, considera-se que o primeiro if está vazio. Nesse momento, A obtém o bloqueio e executa o segundo nível de julgamento se. A condição é estabelecida e um objeto é novo;

B espera na camada externa, A é criado, o bloqueio é liberado, B obtém o bloqueio e o segundo nível se o julgamento é executado. A condição não é estabelecida e o bloqueio é liberado. Quando C chama getSingleton, o primeiro nível de julgamento não é estabelecido e o objeto singleton é retornado diretamente para evitar entrar no bloqueio e reduzir a sobrecarga de desempenho.

Compreensão adicional: dois deles estão vazios, o primeiro vazio é para reduzir o número de vezes para entrar no bloco de código de sincronização no caso de multithreading, e o segundo vazio é para evitar multithreading (A, B no caso de dois threads) , B chama o método getSingleton ao mesmo tempo e, ao mesmo tempo, entra na primeira camada if (singleton == null) {}. Em condições de corrida, se A obtém o bloqueio do objeto, entra no bloco de código síncrono, e B blocos esperando, esperando Depois que o objeto de instância é criado e o bloqueio é liberado, B entra no bloco de código de sincronização, mas neste momento o segundo nível se (singleton == null) {} julga que o singleton não está vazio e retorna o singleton diretamente );

Resumo: há duas instruções para determinar se ele está vazio. A primeira vez é para melhorar a eficiência e evitar a execução de blocos de código sincronizados a cada vez. A segunda vez é para evitar a insegurança causada pelo multithreading. Quando dois threads julgam que o primeiro está vazio ao mesmo tempo, eles entrarão no bloco de código de sincronização um após o outro. Neste momento, se não houver uma segunda condição de vazio, várias instâncias serão criadas.

palavras-chave volite:

É necessário usar modificação de palavra-chave volátil

Na verdade, esse código é dividido em três etapas:

singleton = novo Singleton ();

  1. Alocar espaço de memória para singleton
  2. Inicializar singleton 
  3. Aponte o singleton para o endereço de memória alocado.
    No entanto, jvm tem as características de rearranjo de instruções e a ordem de execução pode mudar, não na ordem de 123, mas pode ser de 132, o que fará com que um thread obtenha uma instância não inicializada
    , como : t1 é executado 13. Neste momento, depois que t2 chama getInstance (), verifica-se que o singleton não está mais vazio, então o singleton é retornado, mas neste momento, o singleton não foi inicializado
    volátil e o rearranjo da instrução jvm pode ser proibido para garantir que pode ser normal em um ambiente multithread executado

Quer saber mais: Recomendar

Compreensão aprofundada do princípio de implementação sincronizada da simultaneidade Java

https://blog.csdn.net/javazejian/article/details/72828483

 

referência:

https://blog.csdn.net/jlnu0812407/article/details/102836187

https://blog.csdn.net/faye_1008/article/details/90296173

Acho que você gosta

Origin blog.csdn.net/JHON07/article/details/103048352
Recomendado
Clasificación