AnthonyZero's Bolg

设计模式:单例模式

概要

单例(Singleton)是一种创建型模式,指某个类采用Singleton模式,则在这个类被创建后,只可能产生一个实例供外部访问,并且提供一个全局的访问点。
核心知识点如下:
(1) 将类的构造方法私有化(采用private修饰)。
(2) 在其内部产生该类的实例化对象,并将其封装成private static类型。
(3) 定义一个静态方法返回该类的实例

应用场景:配置文件、工具类、线程池、缓存、日志对象等

饿汉模式

public class Singleton {

    // 构造函数私有化,不允许外部直接创建对象
    private Singleton() {

    };

    // 创建类的唯一实例
    private static Singleton instance = new Singleton();

    // 提供了一个供外部访问本实例的静态方法,可以直接访问
    public static Singleton getInstance() {
        return instance;
    }

}
  • 优点:线程天生安全,不存在多线程同步问题,避免了synchronized所造成的性能问题;
  • 缺点: 在类创建的同时就实例化一个静态对象出来,不管之后会不会使用这个单例,都会占据一定的内存,但是相应的,在第一次调用时速度也会更快,因为其资源已经初始化完成,

懒汉模式

//线程安全简单实现
public class Singleton {

    //构造函数私有化,不允许外部直接创建对象
    private Singleton(){

    }

    //声明类的实例,不实例化
    private static Singleton instance;

    //提供了一个供外部访问本实例的静态方法,在第一次调用此方法时才实例化对象
    //synchronized为了解决线程不安全的问题,如果没有 synchronized,
    //那么使用 getInstance()是有可能得到多个Singleton
    public static synchronized Singleton getInstance(){
        if(instance == null){
            instance = new Singleton();
        }
        return instance;
    }
}
  • 优点:使用synchronized关键字避免多线程访问时,出现多个Singleton实例。相对于饿汉式在某些特定条件下会节约了内存。
  • 缺点:同步方法频繁调用,效率略低影响性能;延迟加载,在第一次使用该单例的时候才会实例化对象出来。

单例模式最优方案

//线程安全  并且效率高
public class Singleton { 

    // 定义一个私有构造方法
    private Singleton() { 

    }   
    //定义一个静态私有变量(不初始化,不使用final关键字,使用volatile保证了多线程访问时instance
    //变量的可见性,避免了instance初始化时其他变量属性还没赋值完时,被另外线程调用)
    private static volatile Singleton instance;  

    //定义一个共有的静态方法,返回该类型实例
    public static Singleton getInstance() { 
        // 对象实例化时与否判断(不使用同步代码块,instance不等于null时,直接返回对象,提高运行效率)
        if (instance == null) {
            //同步代码块(对象未初始化时,使用同步代码块,保证多线程访问时对象在第一次创建后,不再重复被创建)
            synchronized (Singleton.class) {
                //未初始化,则初始instance变量
                if (instance == null) {
                    instance = new Singleton();   
                }   
            }   
        }   
        return instance;   
    }   
}