单例模式
概述
单例模式就是要确保类在内存中只有一个对象,
该实例必须自动创建,并且对外提供优点:
在系统内存中只存在一个对象,因此可以节约系统资源,
对于一些需要频繁创建和销毁的对象单例模式可以提高系统性能缺点:
没有抽象层,因此扩展很难
职责过重,在一定程序上违背了单一职责实现:
- 构造方法私有
- 在成员位置创建一个对象,对象为私有(防止外界改变)静态
- 公共静态方法提供访问
分类:
饿汉式:类一加载就创建对象 (开发中,Java中的Runtime类)
懒汉式:用的时候,才去创建 (面试中)懒汉式问题:
延迟加载
线程安全问题,需要加synchronized
饿汉式
public class Singleton {
//1.构造方法私有
private Singleton() {}
//2.在成员位置创建一个对象,对象为私有(防止外界改变)静态 (类一加载就创建对象)
private static Singleton instance = new Singleton();
//3.提供一个访问的方法
public static Singleton getInstance(){
return instance;
}
}
懒汉式
public class Singleton {
//1.构造方法私有
private Singleton() {}
//2.在成员位置创建一个对象,对象为私有(防止外界改变)静态
private static volatile Singleton instance = null;
//3.提供一个访问的方法
public static Singleton getInstance(){
if(instance == null){
synchronized (Singleton.class) {
if(instance == null){
return instance = new Singleton();
}
}
}
return instance;
}
}
volatile
:作为禁止指令重排,保证返回Singleton对象一定在创建对象后。instance = new Singleton();语句非原子性,实际会执行以下内容:1.在堆上开辟空间;2.属性初始化;3.引用指向对象。
在单线程的情况下,指令重排不会有影响(正常顺序为1→2→3,重排后顺序可能为:1→3→2)
在多线程的情况下,指令重排后可能会导致返回的对象为空
volatile关键字可保证指令的顺序执行。
第一层null检
:检测是否有引用指向对象,高并发情况下会有多个线程同时进入。
锁
:保证只有一个线程进入
双重检查
:防止多个线程同时进入第一层检查(因单例模式值允许存在一个对象,故在创建对象之前无引用指向对象,所有线程均可进入第一层检查)
当某一线程获得锁创建一个Singleton对象是,即已有引用指向对象,Singleton不为空,从而保证只会创建一个对象。
假设没有第二层检查,那么第一个线程创建完对象释放锁后,后面进入的线程也会创建对象,会产生多个对象