阅读前须知:原文博客请访问 merengues.top
单例模式
单例模式(singleton)保证一个类只有一个实例,并且提供了一个访问全局访问点。
适用性
- 当类只能有一个实例而且客户可以从一个访问点访问它时。
- 当这个实例应该通过子类化可扩展的,并且客户无须更改代码就能使用拓展的实例。
结构
效果
- 对唯一实例的受控访问 Singleton可以严格控制用户怎样以及何时访问它。
- 缩小名字空间 Singleton可以避免全局变量污染命名空间。
- 允许对操作和表示的精化 Singleton类可以有子类,可以用所需要类的实例在运行时配置应用。
- 允许可变数目的实例
类别
懒汉式
使用时创建实例。
优点:第一次调用的时候才初始化,避免内存浪费。
缺点:必须加锁才能保证线程安全,加锁则会影响性能。
饿汉式
类加载时就创建实例。
优点:不用加锁就能保证线程安全,执行效率高。
缺点:类加载就初始化,内存浪费。
实现
懒汉式
1)示例1
public class Singleton{
private static Singleton instance;
private Singleton(){};
public static Singleton getInstance(){
if(instance == null){
instance = new Singleton();
}
return instance;
}
}
线程不安全,避免使用。
2)示例2
public class Singleton{
private static Singleton instance;
private Singleton(){};
public static synchronized Singleton getInstance(){
if(instance == null){
instance = new Singleton();
}
return instance;
}
}
线程同步,线程安全,效率低,避免使用。
3)示例3
public class Singleton{
private static Singleton instance;
private Singleton(){};
public static Singleton getInstance(){
if(instance == null){
synchronized(Singleton.class){
instance = new Singleton();
}
}
return instance;
}
}
线程不安全,会产生多个实例,不可用
饿汉式
1)示例1
public class Singleton{
private static Singleton instance = new Singleton;
private Singleton(){};
public static Singleton getInstance(){
return instance;
}
}
2)示例2
public class Singleton{
private static Singleton instance = null;
static{
instance = new Singleton;
}
private Singleton(){};
public static Singleton getInstance(){
return instance;
}
}
无线程安全问题,影响系统效率,不推荐
双重校验锁
public class Singleton{
private static Singleton instance;
private Singleton(){};
public static Singleton getInstance(){
if(instance == null){
synchronized(Singleton.class){
if(instance == null){
instance = new Singleton();
}
}
}
return instance;
}
}
双重校验锁,线程安全,懒加载,推荐使用
静态内部类
public class Singleton{
private static class SingletonHolder{
private static final Singleton INSTANCE = new Singleton();
}
private Singleton(){}
public static final Singleton getInstance(){
return SingletonHolder.INSTANCE;
}
}
静态内部类,线程安全,主动调用才示例化,懒加载效率高,推荐使用
枚举
public enum Singleton{
INSTANCE;
private Singleton(){};
public static Singleton getInstance(){
return INSTANCE;
}
}
枚举类型,无线程安全问题,避免序列化创建新实例,使用少;
注意事项
- 考虑多线程问题
- 如果类可序列化,考虑反序列化生成多个实例问题,解决方法如下:
private Object readResolve() throw ObjectStreamException{
/**
*在类中添加readResolve方法返回单例对象
**/
return instance;
}
- 反射会破坏单例模式,避免用反射创建单例对象:
private Singleton(){
if(instance != null){
throw new RuntimeException("禁止反射创建单例对象");
}
}
/**
*在类中添加readResolve方法返回单例对象
**/
return instance;
}
- 反射会破坏单例模式,避免用反射创建单例对象:
private Singleton(){
if(instance != null){
throw new RuntimeException("禁止反射创建单例对象");
}
}