单例模式
2020-07-15 09:49:45 10 举报
AI智能生成
设计模式之单例
作者其他创作
大纲/内容
Why
一个类只允许创建唯一一个实例
唯一性是在进程层面的
处理问题
处理资源访问冲突
锁不解决问题,例如FileWriter写入同一个文件
利用并发队列解决,如Java中的BlockingQueue
复杂
表示全局唯一类
配置信息类
唯一递增的ID号码生成器
How
构造函数private属性
考虑对象创建时的线程安全
考虑是否支持延迟加载
考虑getInstance性能是否高效
是否加锁
实现
饿汉式/Eager Loading
类加载时,就实例化单例
实现
定义static final
private constructor
不能调用
用一个方法供调用instance
例如:public static Helper getInstance()
优缺点
简单实用
线程完全
类加载的时候就是实例化,不管是否用到
其实早初始化并非总是不好。避免在用到的时候初始化时间长,影响性能
如果占用资源多,根据fail-fast原则,早初始化,如果fail可以早些介入。
饿汉式02
用static block:
static {
INSTANCE = new Helper();
}
实现
static {
INSTANCE = new Helper();
}
实现
Lazy Loading
用的时候才初始化
实现
当调用getInstance的时候,测试INSTANCE == null
INSTANCE 不能为final
public static Helper getInstance() {
if (INSTANCE == null) {
INSTANCE = new Helper();
}
return INSTANCE;
}
if (INSTANCE == null) {
INSTANCE = new Helper();
}
return INSTANCE;
}
优势
支持延迟加载
问题
线程不安全
核心原因:线程的执行顺序不确定性
不可控
不可控
Lazy Loading with Lock
on method
on method
在方法上加锁
public static synchronized Helper getInstance() {
......
}
......
}
线程安全
问题
加锁
加锁expensive,效率降低
并发度降低
lazy Loading
减少synchronized scope
public static Help getInstance () {
if (INSTANCE == null) {
synchronized (Helper.class) {
INSTANCE = new Helper();
}
}
}
if (INSTANCE == null) {
synchronized (Helper.class) {
INSTANCE = new Helper();
}
}
}
线程不安全
问题
判断为null和new对象没有作为一个整体来操作,多线程有问题
Lazy Loading with DCL
DCL
为什么要判断两次
锁的成本高,判断null的成本低
在多线程情况下,performance更好
在多线程情况下,performance更好
INSTANCE 应该 volatile 限制
因为每次操作volatile变量都存在读/写内存,
速度受到影响
速度受到影响
优化Tips: 在锁内部,不要直接引用volatile变量,
可以先用一个临时变量,到最后才赋给volatile变量
可以先用一个临时变量,到最后才赋给volatile变量
线程安全
not compatible with Java 1.4 and lower versions because of "volatile"
静态内部类/
Initialization-on-demand Holder idiom
Initialization-on-demand Holder idiom
private static class HelperHolder {
private final static Helper INSTANCE = new Helper();
}
public static Helper getInstance() {
return HelperHolder.INSTANCE;
}
private final static Helper INSTANCE = new Helper();
}
public static Helper getInstance() {
return HelperHolder.INSTANCE;
}
当类被加载时,其内的静态内部类是不会被加载的。
JVM保证对一个类只加载一次
不用加锁
线程安全
非常快
enum
可以解决线程同步,还可以防止反序列化
原因:枚举类没有构造方法
public enum Helper {
INSTANCE;
.....
}
INSTANCE;
.....
}
线程安全
非常快
存在问题
对OOP特性支持不友好
会隐藏类之间的依赖关系
对代码的可测试性不友好
对代码的扩展性不友好
不支持有参数的构造函数
替代解决方案
静态方法实现
工厂模式
IOC容器
程序员自己
“唯一”的几种情况
进程唯一
单例模式
线程唯一
利用HashMap
参考ThreadLocal实现
集群唯一
对单例对象序列化,并存储到外部共享区。
使用的时候,每一个进程加锁,然后载入内存,反序列化成对象,再使用。
使用的时候,每一个进程加锁,然后载入内存,反序列化成对象,再使用。
多例模式
含义
指一个类可以创建制定个数个对象
一个类可以创建不同类型的几个对象
如Logger 对不同文件就可以对应一个对象
实现思路
通过Map来存储对象类型和对象之间的对应关系
0 条评论
下一页