在23种设计模式中单例模式算是比较简单的一种设计模式了,虽然简单,但是他的实现却有很多种。下面会给出两种最佳实现和其他一些常见的实现方式。
单元素枚举
不需要延迟加载时的最佳实现
public enum Singleton {
//每个元素就是一个单例
INSTANCE;
//业务方法
public void method(){}
}
优点:
- 能防止反射
- 能防序列化
- 线程安全
- 调用效率高
缺点:
- 不能延时加载
静态内部类
需要延迟加载时的最佳实现
public class Singleton {
//1. 创建私有的 静态内部类
private static class inner {
//1.1 在静态内部类里,创建 私有的 静态的 外部类对象
private static Singleton instance = new Singleton();
}
//2. 私有化构造器,禁止他人创建实例
private Singleton() {
}
//3. 创建 公开的 静态的 获取实例的方法
public static Singleton getInstance() {
return inner.instance;
}
}
优点:
- 线程安全
- 调用效率高
- 能延时加载
缺点:
- 不能能防止反射
- 不能防序列化
饿汉式
public class Singleton {
//1. 创建私有的 静态的内部实例
private static Singleton instance = new Singleton();
//2. 私有化构造器,禁止他人创建实例
private Singleton(){}
//3. 创建 公开的 静态的 获取实例的方法
public static Singleton getInstance(){
return instance;
}
}
优点:
- 线程安全
- 调用效率高
缺点:
- 不能能防止反射
- 不能防序列化
- 不能延时加载
懒汉式
public class Singleton {
//1. 创建私有的 静态的内部实例,并初始化为null
private static Singleton instance = null;
//2. 私有化构造器,禁止他人创建实例
private Singleton() {
}
//3. 创建 公开的 静态的 获取实例的方法
public static Singleton getInstance() {
// 先判断单例是否为空,以避免重复创建
if( instance == null){
instance = new Singleton();
}
return instance;
}
}
优点:
- 能延时加载 缺点:
- 不能能防止反射
- 不能防序列化
- 线程不安全
- 调用效率不高
懒汉式 + 同步锁
public class Singleton {
//1. 创建私有的 静态的内部实例,并初始化为null
private static Singleton instance = null;
//2. 私有化构造器,禁止他人创建实例
private Singleton() {
}
//3. 创建 公开的 静态的 获取实例的方法
public static synchronized Singleton getInstance() {
// 加入同步锁
if (instance == null)
instance = new Singleton();
return instance;
}
}
优点:
- 能延时加载
- 线程安全 缺点:
- 不能能防止反射
- 不能防序列化
- 调用效率不高
双重校验锁(懒汉式的改进)
注意:JVM的指令重排序,可能会导致双重校验锁失效
public class Singleton {
//1. 创建私有的 静态的内部实例,并初始化为null
private static Singleton instance = null;
//2. 私有化构造器,禁止他人创建实例
private Singleton() {
}
//3. 创建 公开的 静态的 获取实例的方法
public static Singleton getInstance() {
// 加入双重校验锁
// 校验锁1:第1个if
if( instance == null){
synchronized (Singleton.class){
// 校验锁2:第2个 if
if( instance == null){
instance = new Singleton();
}
}
}
return instance;
}
}
优点:
- 能延时加载
- 线程安全 缺点:
- 不能能防止反射
- 不能防序列化
- 调用效率不高
双重校验锁优化(规避指令重排序的影响)
使用 volatile 关键字来防止指令重排序
public class Singleton {
//1. 创建私有的 静态的 可见的 内部实例,并初始化为null
private static volatile Singleton instance = null;
//2. 私有化构造器,禁止他人创建实例
private Singleton() {
}
//3. 创建 公开的 静态的 获取实例的方法
public static Singleton getInstance() {
// 加入双重校验锁
// 校验锁1:第1个if
if( instance == null){
synchronized (Singleton.class){
// 校验锁2:第2个 if
if( instance == null){
instance = new Singleton();
}
}
}
return instance;
}
}
优点:
- 能延时加载
- 线程安全 缺点:
- 不能能防止反射
- 不能防序列化
- 调用效率不高