介绍
作用
保证一个类仅有一个实例,并提供一个访问它的全局访问点。
注意
- 单例类只能有一个实例。
- 单例类必须自己创建自己的唯一实例。
- 单例类必须给所有其他对象提供这一实例。
优点
- 在内存里只有一个实例,减少了内存的开销,尤其是频繁的创建和销毁实例。
- 避免对资源的多重占用。
缺点
- 没有接口,不能继承,与单一职责原则冲突,一个类应该只关心内部逻辑,而不关心外面怎么样来实例化。
懒汉式—线程不安全
最基础的实现方式,线程上下文单例,不需要共享给所有线程,也不需要加synchronize之类的锁,以提高性能。
懒汉式—线程安全
加上synchronize之类保证线程安全的基础上的懒汉模式,相对性能很低,大部分时间并不需要同步。
特点
- 线程安全
- 能延迟加载
- 调度效率不高
//懒汉式单例
public class Singleton{
//1、私有化构造器
private Singleton(){}
//2、类初始化的时候,加载该对象。
private static Singleton instance;
//3、提供获取该对象的方法,有synchronized,效率不高。
public static synchronized Singleton getInstance() {
if (instance == null) {
instance = new Singleton();
}
return instance;
}
}
饿汉方式
指全局的单例实例在类装载时构建。
特点
- 线程安全
- 不能延迟加载
- 调度效率高
//饿汉式单例
public class Singleton{
//1、私有化构造器
private Singleton(){}
//2、类初始化的时候,加载该对象。
private static Singleton instance = new Singleton();
//3、提供获取该对象的方法,没有synchronized,效率高。
private static Singleton getInstance(){
return instance;
}
}
双检锁/双重校验锁(DCL,即 double-checked locking)
在懒汉式基础上利用synchronize关键字和volatile关键字确保第一次创建时没有线程间竞争而产生多个实例,仅第一次创建时 同步,性能相对较高
//DCL饿汉式单例
public class Singleton{
//1、私有化构造器
private Singleton(){}
//2、类初始化的时候,加载该对象。
//volatile可以避免指令的重排。
private volatile static Singleton instance;
//3、提供获取该对象的方法,有synchronized,效率高。
public static Singleton getInstance() {
if (instance == null) {
synchronized (Singleton.class) {
if(instance==null) {
instance = new Singleton();
}
}
}
return instance;
}
}
登记式/静态内部类
作为创建类的全局属性存在,创建类被装载时创建
特点
- 线程安全
- 能延迟加载
- 调度效率高
//静态内部类
public class Singleton{
//1、私有化构造器
private Singleton(){}
//2、调用该方法时,加载该对象。
private static class SingletonHolder {
private static final Singleton instance = new Singleton();
}
public static final Singleton getInstance() {
return SingletonHolder.instance;
}
}
枚举
java中枚举类本身也是一种单例模式
特点
- 线程安全
- 不能延迟加载
- 调度效率高
//枚举
public enum Singleton {
instance;
public void whateverMethod() {
}
}