本笔记主要摘自菜鸟教程,代码重新实现了一遍,方便自己复习。之后会陆续再增加其他设计模式,进行完善,如果想认真学习,可以去菜鸟官网学习。
单例
1. 懒汉式,线程不安全
是否lazy初始化:是
是否多线程安全:否
实现难度:易
描述:这种方式是最基本的实现方式,最大的问题是不支持多线程,因为没有加锁,严格意义不算单例模式,这种方式lazyloading很明显,不要求线程安全。
public class Singleton {
private static Singleton instance;
private Singleton(){}
public static Singleton getInstance(){
if(instance==null){// 很多线程都会进来
instance = new Singleton();
}
return instance;
}
}
2. 懒汉式,线程安全
是否lazy初始化:是
是否多线程安全:是
实现难度:易
描述:这种方式具备很好的lazyloading,能够在多线程中很好的工作,但是效率低。
优点:第一次调用才初始化,避免内存浪费
缺点:必须加锁才能保证单例,但加锁影响效率。
public class Singleton {
private static Singleton instance;
private Singleton(){}
public static synchronized Singleton getInstance(){
if(instance==null){
instance = new Singleton();
}
return instance;
}
}
3. 饿汉式
是否lazy初始化:否
是否多线程安全:是
实现难度:易
描述:这种方式较常用,但易产生垃圾对象
优点:没有加锁,执行效率高
缺点:类加载时就初始化,浪费内存
基于classloader机制避免多线程的同步问题,不过,instance在类加载时就实例化,
public class Singleton {
// 静态就已经new了
private static Singleton instance = new Singleton();
private Singleton(){}
public static Singleton getInstance(){
return instance;
}
}
4. 双检锁/双重校验锁
DCL即double-checked locking
JDK版本:1.5以后
是否lazy初始化:是
是否多线程安全:是
实现难度:较复杂
描述:采用双锁机制,安全且在多线程下能保证高性能
public class Singleton {
private volatile static Singleton singleton;
private Singleton(){}
public static Singleton getInstance(){
// 大部分情况下都不为空,直接返回,提高效率
if(singleton==null){
synchronized (Singleton.class){
// 解决单例的判断
if(singleton==null){
singleton=new Singleton();
}
}
}
return singleton;
}
}
5. 登记式/静态内部类
是否lazy初始化:是
是否多线程安全:是
实现难度:一般
描述:这种方式能达到双检锁方式一样的效果,但实现更简单。同样利用classloader机制保证初始化instance时只有一个线程。只有通过显式调用getInstance方法时,才会显式装载SingletonHolder类,从而实例化instance。一方面实例化instance消耗资源,另一方面,不希望Singleton类加载时就实例化,因为不能确保Singleton类还可能在其他地方主动使用从而被加载,这个时候实例化不合适。
public class Singleton {
// 静态内部类,只有调用它的时候才会初始化
private static class SingletonHolder{
private static final Singleton INSTANCE = new Singleton();
}
private Singleton(){}
public static final Singleton getInstance(){
return SingletonHolder.INSTANCE;
}
}
6. 枚举
JDK版本:1.5后
是否lazy初始化:否
是否多线程安全:是
实现难度:易
描述:这种方式是实现单例模式的最佳方法,更简洁,自动支持序列化机制,绝对防止多次实例化
因为1.5以后才加入,实际应用较少
public enum Singleton {
INSTANCE;
public void whateverMethod(){}
}
总结
一般建议使用第三种饿汉方式,只有明确lazyloading时,使用第5种静态内部类方式,涉及反序列化,使用第6种枚举方式。有其他特殊需求,考虑第4种双检锁方式。