软件设计模式之单例模式
设计模式之单例模式
定义
保证一个类仅有一个实例,并提供一个全局访问点
类型
创建型
使用场景
想确保任何情况下都绝对只有一个实例
优点
在内存里只有一个实例,减少了内存开销。
可以避免对资源的多重占用。
设置全局访问点,严格控制访问。
缺点
没有接口,扩展困难
重点
- 私有构造器
- 线程安全
- 延迟加载,想使用的时候再创建
- 序列化和反序列化安全
- 反射:防止反射攻击
实用技能
- 反编译
- 内存原理
- 多线程Debug
相关设计模式
- 单例模式和工厂模式
- 单例模式和享元模式
懒汉模式
在需要的时候才实例化对象。
但是这种模式会存在线程安全问题。
传统懒汉模式
代码如下:
public class LazySingleton {
private static LazySingleton lazySingleton = null;
/**
* 私有构造器
*/
private LazySingleton() {
}
public static LazySingleton getInstance() {
if (lazySingleton == null) {
lazySingleton = new LazySingleton();
}
return lazySingleton;
}
}
双重检查懒汉模式
public class LazyDoubleCheckSingleton {
private static volatile LazyDoubleCheckSingleton lazyDoubleCheckSingleton = null;
private LazyDoubleCheckSingleton() {
}
public static LazyDoubleCheckSingleton getInstance() {
if (lazyDoubleCheckSingleton == null) {
synchronized (LazyDoubleCheckSingleton.class) {
if (lazyDoubleCheckSingleton == null) {
lazyDoubleCheckSingleton = new LazyDoubleCheckSingleton();
}
}
}
return lazyDoubleCheckSingleton;
}
}
JVM创建对象有以下几步:
1、给对象分配内存空间;
2、初始化对象;
3、设置实例
指向刚分配的内存地址;
4、初次访问对象。
但是在实际的创建对象的过程中,2,3两步有可能出现指令重排,也就是先执行3,2的顺序,这种改变在单线程中是没有问题的,实际在多线程中也没太大的问题,只是出现极端情况下,会出现问题,如下图所示:
volatile
有两个作用:内存可见性和禁止指令重排。在这段代码中保证了指令的顺序性,不会重排序。
案例
- 线程池
- 日志操作