概述
- 单例模式最常见最常问到的设计模式
- 单例设计模式(Singleton),即某个类在整个系统中只能有一个实例
- 比如:代表JVM运行环境的Runtime类、代表某类信息的XxxClass、spring-IOC容器bean等
- 关键点
- 构造器私有化——保证外部不能随意new出新实例
- 类自身提供该实例——通过静态变量或者静态方法
- 设计分类
- 按实例化时机可分为 饿汉式 和 懒汉式
- 饿汉式特点是类加载时创建实例对象,不论是否会用到该实例。优点是简单、线程安全,缺点是资源占用。
- 懒汉式则是延迟实例创建,在需要该类实例时才进行实例化,懒汉式缺点是需要注意线程安全问题。
饿汉式几种写法
最经典写法
public class Eager01 {
//构造器私有化
private Eager01() {}
//public + static,提供外部直接类名获取
//final 强调单例
public static final Eager01 INSTANCE = new Eager01();
}
枚举写法
- 使用枚举的单例设计以及成为现在最为优雅推崇的方式,优点很多
- 优点:写法简单优雅; 线程安全; 可应对反射攻击; 序列化支持...
- 唯一缺点:因为枚举类以及继承 Enum, 所以不能再继承拓展。严格的说,这算不上缺点..
- 写法角度可以视为经典写法的简洁翻版
//理解:
//枚举类型即其实例为限定范围的几个,我们只提供一个,那么就是单例
public enum Eager2_enum {
INSTANCE;
}
静态代码块写法
- 适用于实例化时需要复杂逻辑处理的场景,比如加载属性文件等
- 这些实例化处理在静态代码块中完成
public class Eager3_static_block {
private Eager3_static_block() {}
public static Eager3_static_block instance;
static {
//...其他操作,比如资源属性文件加载等
instance = new Eager3_static_block();
}
}
- 单例最好加上 final,使用 private staic 方法
public class Eager3_static_block {
private Eager3_static_block() {}
public final static Eager3_static_block INSTANCE = init();
// static {
// //...其他操作,比如资源属性文件加载等
// INSTANCE = new Eager3_static_block();
// }
private static Eager3_static_block init() {
return new Eager3_static_block();
}
}
懒汉式几种写法
简单延迟实例版 - 非线程安全
public class Lazy01 {
//还是一样,构造器私有化
private Lazy01() {}
//静态私有变量
private static Lazy01 instance;
//提供public静态方法以获取实例
public static Lazy01 getSingleton() {
if(null == instance) {
instance = new Lazy01();
}
return instance;
}
}
线程安全 - 静态方法同步版
public class Lazy2 {
//还是一样,构造器私有化
private Lazy2() {}
//静态私有变量
private static Lazy2 instance;
//提供public静态方法以获取实例,静态方法加锁
public synchronized static Lazy2 getSingleton() {
if(null == instance) {
instance = new Lazy2();
}
return instance;
}
}
性能与安全兼顾 - 双重检查同步锁版
public class Lazy3 {
//还是一样,构造器私有化
private Lazy3() {}
//静态私有变量
private static Lazy3 instance;
//提供public静态方法以获取实例
public static Lazy3 getSingleton() {
if(null == instance) { //第一次检查,提高性能,只有第一次为null时才触发锁
synchronized (Lazy2.class) {
if(null == instance) { //第二次检查,安全考虑,防止线程同时通过第一次检查
instance = new Lazy3();
}
}
}
return instance;
}
}
优雅懒汉式 - 静态内部类版
- 同使用枚举的懒汉式一样,属于优雅且受推崇的单例设计
- 使用静态内部类,内部饿汉式,外部懒汉式,很巧妙,又避免了使用同步锁
public class Lazy4 {
//还是一样,构造器私有化
private Lazy4() {}
//静态内部类
private static class Inner {
//饿汉式
private static final Lazy4 INSTANCE = new Lazy4();
}
//外部懒汉式(调用此方法才会加载内部类,创建 INSTANCE 实例)
public static Lazy4 getSingleton() {
return Inner.INSTANCE;
}
}