Spring设计模式-实战篇之单例模式

  实现案例,饿汉式 + Double-Check机制 + synchronized锁

/**
 * 以饿汉式为例
 * 使用Double-Check保证线程安全
 */
public class Singleton {

    // 使用volatile保证多线程同一属性的可见性和指令重排序
    private static volatile Singleton instance;

    public static Singleton getInstance() {
        // 第一次check
        if (instance == null) {
            synchronized (Singleton.class) {
                // 第二次check
                if (instance == null) {
                    instance = new Singleton();
                }
            }
        }
        return instance;
    }

}

1、两次check的作用

第一次check:为了提高效率,假如我的instance已经不为null了,就没必要进入同步代码块了;

第二次check:因为在没有获取实例之前,即instance为null之前,可能有多个线程进入了第一个if之内,这个时候为了防止创建多个实例,使用同步代码块,一个线程一个线程进入,当Instance不为null时,才new对象,保证了对象实例只被 new 一次,即保证单例模式。

2、为什么使用了synchonized同步还要加volatile关键字

 首先,synchonized可以保证原子性和可见性,但是他保证不了指令重排序这种情况。

 那指令重排序存在什么问题呢?

当线程A和B分别执行到以上位置时,

 1)对于  instance = new Singleton(); 这个操作,其实分为三个步骤:

  1. JVM为对象分配一块内存;
  2. 在内存上为对象进行初始化;
  3. 将内存的地址赋值给singleton变量;

这样是没有问题的,因为只有把内存地址赋值给singleton变量以后,instance才不等于null,而赋值之前就已经初始化了,所以线程B不会出现误判的情况;

2)但是假如不使用volatile,编译器可能会优化,将2,3替换位置,也就是:

  1. JVM为对象分配一块内存;
  2. 将内存的地址赋值给singleton变量;
  3. 在内存上为对象进行初始化;

这样就可能会出现问题了,场景如下:

        当A线程赋值了以后,还没来得及初始化呢,这个时候线程B刚好判断instance == null,返回false,直接return instance了,但此时这个instance实际上是还没初始化的bean,这样就有问题了。

总结

  1. 懒汉式是线程不安全的,可以通过synchonized进行加锁,保证它的一个线程安全性;
  2. 如果你想提高它的效率,可以使用Double-Check这种机制,让它存在实例以后无需再去竞争锁,在外层 if 即可直接判断;
  3. 当你使用Double-Check这种机制的时候,请注意加上volatile关键字,防止优化器指令重排序带来的影响。

ps:以下是我整理的java面试资料,感兴趣的可以看看。最后,创作不易,觉得写得不错的可以点点关注!

链接:https://www.yuque.com/u39298356/uu4hxh?# 《Java面试宝典》 

相关推荐

  1. Spring设计模式模式

    2024-03-23 20:38:01       48 阅读
  2. Spring设计模式-实战模板方法模式

    2024-03-23 20:38:01       44 阅读
  3. Spring设计模式-实战策略模式 + 工厂模式

    2024-03-23 20:38:01       46 阅读
  4. 【前端设计模式模式

    2024-03-23 20:38:01       60 阅读
  5. 设计模式模式

    2024-03-23 20:38:01       56 阅读
  6. C++设计模式模式

    2024-03-23 20:38:01       58 阅读
  7. 设计模式模式

    2024-03-23 20:38:01       53 阅读
  8. 设计模式模式

    2024-03-23 20:38:01       62 阅读

最近更新

  1. docker php8.1+nginx base 镜像 dockerfile 配置

    2024-03-23 20:38:01       94 阅读
  2. Could not load dynamic library ‘cudart64_100.dll‘

    2024-03-23 20:38:01       100 阅读
  3. 在Django里面运行非项目文件

    2024-03-23 20:38:01       82 阅读
  4. Python语言-面向对象

    2024-03-23 20:38:01       91 阅读

热门阅读

  1. 前端请求传参格式

    2024-03-23 20:38:01       41 阅读
  2. web蓝桥杯真题:折叠手风琴

    2024-03-23 20:38:01       40 阅读
  3. 分布式并行策略概述

    2024-03-23 20:38:01       44 阅读
  4. 国庆节是星期几

    2024-03-23 20:38:01       42 阅读
  5. 为wordpress后台添加一个自定义页面

    2024-03-23 20:38:01       41 阅读
  6. Linux ld链接器

    2024-03-23 20:38:01       30 阅读
  7. server2016datacenter改正式版

    2024-03-23 20:38:01       37 阅读
  8. 苍穹外卖Day3碰到的元注解

    2024-03-23 20:38:01       43 阅读
  9. Eureka注册中心

    2024-03-23 20:38:01       40 阅读