[面试高频问题]关于多线程的单例模式

单例模式

     什么是设计模式?

设计模式可以看做为框架或者是围棋中的”棋谱”, 红方当头炮, 黑方马来跳. 根据一些固定的套路下,能保证局势不会吃亏.

在日常的程序设计中, 往往有许多业务场景, 根据这些场景, 大佬们总结出了一些固定的套路. 按照这个套路来实现代码, 也不会吃亏.

什么是单例模式, 保证某类在程序中只有一个实例, 而不会创建多份实例.

       单例模式具体的实现方式:可分为”懒汉模式”, ”饿汉模式”.

饿汉模式

       类加载的同时,创建实例

       用private修饰构造方法,使外部类无法调用构造方法创建实例

class singleHunger{
    private static singleHunger instance = new singleHunger(); //创建实例
    public  static  singleHungergetInstance(){  //提供方法获取instance
        return instance;
    }
    private singleHunger (){
    }
}

懒汉模式

懒汉模式-单线程版

类加载时不创建实例, 在调用获取实例的方法时,创建实例

用private修饰构造方法,使外部类无法调用构造方法创建实例

class singleLazy{
    public  static  singleLazy instance = null;
  private  singleLazy(){}
    public  static  singleLazygetInstance(){
        if ( instance == null){
            return  instance = new singleLazy(); //创建实例
        }
        return instance;
    }
}

懒汉模式-多线程版

在多线程环境中,使用上面的懒汉模式-单线程版实现 ,在实例首次创建时会有线程安全问题.

线程安全问题分析:

       两个线程调用singleLazygetInstance()方法获取实例, 如果两个线程的if 判断都为 true, 此时两个线程都分别创建了实例, 两个实例互不相同违背了单例模式的唯一实例的设定.

[面试高频问题]关于多线程的单例模式_第1张图片

使用synchronized()进行加锁解决线程安全问题

代码实例:

class singleLazy{
    public  static  singleLazy instance = null;
    static  Object object  = new Object();
    private  singleLazy(){}
    public  static  singleLazy getInstance(){
        synchronized (singleLazy.object) {
            if (instance == null) {
                return instance = new singleLazy();
            }
        }
        return instance;
    }
}

懒汉模式-多线程版(优化)

以下代码在加锁的基础上, 做出了进一步改动:

        使用双重 if 判定, 降低锁竞争的频率.

        给 instance 加上了 volatile.

代码演示:

class singleLazy{
    public  static  singleLazy instance = null;
    static  Object object  = new Object();
    private  singleLazy(){}
    public  static  singleLazy getInstance(){
        if(instance == null){
            synchronized (singleLazy.object) {
                if (instance == null) {
                    return instance = new singleLazy();
                }
            } 
        }
        return instance;
      }

}

理解双重 if 判定 / volatile:

加锁和解锁的操作是非常影响代码效率的, 饿汉模式只有在首次创建实例的时候会出现线程安全问题, 加入双重if判断可以避免频繁的加锁解锁问题.大大提高了代码执行效率.

引入volatile修饰instance, 可以有效避免”代码可见性”和”指令重排序问题”

可能出现指令重排序问题:

 instance = new singleLazy(), 代码指令一共由三个代码命令组成

  1. 申请一段内存
  2. 初始化 singleLazy的类方法和属性
  3. 将实例指向 instance 引用.

如果此顺序被优化成 1 3 2 的话 ,就会导致singleLazy的类方法和属性还未被初始化,但instance已不为null了,就会通过if判断条件返回还未初始化完成的instance,当调用instance的属  性跟方法时就会出现异常.

好了本次的学习分享就到这里了,如果本次分享对你有帮助的话,请点一个免费的赞支持一下作者哦.谢谢啦! 我们下次再见

你可能感兴趣的:(java,单例模式,开发语言)