[剑指offer]面试题02:实现Singleton 模式——6种实现方式

一. 什么是设计模式

参考博客1博客2博客3博客4
1. 设计模式是什么?
设计模式是一套被反复使用,多数人知晓,经过分类编目的的,代码设计经验的总结。特别要说的是:模式并不是代码,而是某类问题的通用 解决方案,说的通俗一点就是很多人都使用的一种办法。
2. 为什么要用设计模式,它到底能帮我们解决什么问题?
设计模式更便于重用代码,让代码更容易被他人理解,也保证了代码的可靠性。

二、什么是单例模式

1.. 设计模式分为三大类:创建型模式、结构性模式、行为型模式,单例模式就是创建型模式中的一种,单例模式要求在系统运行时,只存在唯一的一个实例对象;
应用举例:windows的任务管理器,回收站,web应用的配置对象,打印机等。

三. 单例模式的特点

  1. 单例模式只能有一个实例对象;
  2. 单例类必须创建自己的唯一实例;
  3. 单例类必须向其他对象提供这一实例。

四、单例模式的实现

根据上述3个基本要求,可以知道一下设计要点:
1. 单例模式只能有一个实例对象 —- 需要自定义 private 构造函数,这样构造函数就不会被调用
2. 单例类必须创建自己的唯一实例 —- 类的内部必须有一个对象实例
3. 单例类必须向其他对象提供这一实例 —- 类的内部有public修饰的函数返回内部的对象实例


  1. 懒汉模式
public class Singleton{
    private static Singleton instance = null;

    private Singleton(){    }

    public static Singleton getInstance(){
        if( instance == null){
             instance = new Singleton();
        }
        return instance;
    }
}

如上,通过提供一个静态的对象instance,利用private权限的构造方法和getInstance()方法来给予访问者一个单例。之所以叫做懒汉模式,是因为此种方法可以非常明显的每次必须先判断是否为null,才会加载。
缺点是,没有考虑到 线程安全,可能存在多个访问者同时访问,并同时构造了多个对象的问题;
针对懒汉模式线程不安全的问题,在getInstance()方法前加锁,于是就有了第二种实现。
2. 线程安全的懒汉模式

public class Singleton{
    private static Singleton instance = null;

    private Singleton(){    }

    public static synchronized Singleton getInstance(){
        if( instance == null){
             instance = new Singleton();
        }
        return instance;
    }
}

通过synchronized关键字修饰getInstance()方法,解决的多个线程访问冲突的问题,但是会引入不必要的阻塞:
* 当多个线程调用getInstance()方法时,先允许一个线程调用,其他线程等待,但是当第一个线程调用结束后,单例已经创建了,第二个线程调用时后面的线程依然在等待,这种等待是无意义的,会造成阻塞导致效率降低。
3. 双重校验的懒汉模式

public class Singleton{
    private volatile static Singleton5 instance = null;

    private Singleton(){    }

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

使用 双重校验 的懒汉模式,在进行等待前先判断instance是否为null。
4. 静态类内部加载

public class Singleton{
    private Singleton(){    }

    public static Singleton getInstance(){
        return SingletonInner.instance;
    }

    private static class SingletonInner{
        private static final Singleton instance = new Singleton();
    }
}

使用内部类的好处是,静态内部类只有在调用getInstance()方法时才进行加载,第一次调用getInstance()方法时,会创建实例instance,之后只有在有需要的时候才会再次返回这个实例,实现了按需创建,又是线程安全的。
5. 通过枚举实现
不理解,可以在前面引用的博客中自行查看。

其他

  1. 饿汉模式
    与懒汉模式相对应的是“饿汉模式”,代码如下:
public class Singleton{
    private static Singleton instance = new Singleton();

    private Singleton(){    }

    public static Singleton getInstance(){
        return instance;
    }
}

在类初始化执行到静态属性时,就分配了资源,之后可以直接使用通过方法访问。显然,这种方法没有起到懒汉模式的lazy loading效果,和懒汉模式相比,只是多了一个内存常驻而已。

猜你喜欢

转载自blog.csdn.net/smj19920225/article/details/80185560