java提高之设计模式

本笔记主要摘自菜鸟教程,代码重新实现了一遍,方便自己复习。之后会陆续再增加其他设计模式,进行完善,如果想认真学习,可以去菜鸟官网学习。

单例

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种双检锁方式。

猜你喜欢

转载自blog.csdn.net/wjl31802/article/details/91360815