认识设计模式(一)---单例模式(5)

(一)懒汉式(双重检查)

(1)步骤如下:

  1. 构造器私有化(防止new再获取对象)
  2. 类的内部创建对象(但是不急着实例化)
  3. 第一次check:提供一个公有的静态方法,当使用到这个方法时,先判断对象是不是null,加入同步synchronized处理的代码,解决线程安全问题,如果为null再去第二次check
  4. 第二次check:如果多线程同时进入if语句,这时候再“同步”一次,然后才对象实例化

(2)单例类代码如下:

class Singleton05{
    //1-构造器私有化
    private Singleton05(){ }
    //2-本类内部创建对象实例
    private static volatile Singleton05 instance;
    //3-提供一个公有的静态方法,当使用到这个方法时,才去创建instance
    // 加入同步synchronized处理的代码,解决线程安全问题(同步就是每次只能有一个线程获取)
    // 加入双重检查代码,解决线程安全问题,同时解决懒加载问题,同时保证了效率
    // 推荐使用
    // 懒汉式
    public static synchronized Singleton05 getInstance(){
        if(instance==null){
            synchronized (Singleton05.class){
                if(instance==null){
                    instance=new Singleton05();
                }
            }
        }
        return instance;
    }
}

(3)测试类代码如下

public class SingletonTest05 {
    public static void main(String[] args) {
        Singleton05 instance01=Singleton05.getInstance();
        Singleton05 instance02=Singleton05.getInstance();
        System.out.println(instance01==instance02);
        System.out.println("instance01-hashCode="+instance01.hashCode());
        System.out.println("instance02-hashCode="+instance02.hashCode());
    }
}

(二)优缺点分析

  1. double-check:是多线程开发中常使用的,进行了两次if检查,就可以保证线程安全了
  2. 示例代码只有执行一次,后面再次访问时,判断if,直接return实例化对象,也避免反复进行方法同步
  3. 线程安全:延迟加载,效率较高
  4. 所以说:在实际开发中,推荐使用这种单例设计模式

(三)与懒汉式(前两个)的区别

  1. 懒汉式(线程不安全):没使用synchronized,只能在单线程下使用
  2. 懒汉式(线程安全):使用了synchronized,每次只能一个线程进入if语句,能在多线程下使用,但是效率太低
  3. 懒汉式(双重检查):使用了两个synchronized,先check进入if语句,再check进行实例化对象
    public static synchronized Singleton04 getInstance(){
        if(instance==null){
            instance=new Singleton04();
        }
        return instance;
    }

改成了

    public static synchronized Singleton05 getInstance(){
        if(instance==null){
            synchronized (Singleton05.class){
                if(instance==null){
                    instance=new Singleton05();
                }
            }
        }
        return instance;
    }

为什么使用double check?

可能会有多个线程通过第一个if(instance==null)的check,判断对象有没有被实例化,如果没有被实例化就往下走,每个线程会依次获得锁进入临界区。
进入临界区后还要再判断一次单例类是否已被其它线程实例化,如果没有被实例化再进行实例化对象,以避免多次实例化。

发布了41 篇原创文章 · 获赞 5 · 访问量 676

猜你喜欢

转载自blog.csdn.net/weixin_44823875/article/details/104786263