单例设计模式 (1)
最编程
2024-03-31 10:06:24
...
单例设计模式(1)
本文已一个ID生成器代码为例,实现设计的模式的改进
介绍
概念
- 一个类只允许创建一个对象(或者叫实例),那这个类就是一个单例类
单例的用处
从业务概念上,有些数据在系统中只应该保存一份,就比较适合设计为单例类。比如,系统的配置信息类。除此之外,我们还可以使用单例解决资源访问冲突的问题。
饿汉式
基本单例的实现
public class IdGenerator {
/**
* Id值
*/
private AtomicInteger id = new AtomicInteger(0);
/**
* 实例对象
*/
private static IdGenerator instance = new IdGenerator();
/***
* 私有化构造方法
*/
private IdGenerator() {
}
/**
* 获取实例
*
* @return
*/
public static IdGenerator getInstance() {
return instance;
}
/**
* 获取下一个ID
*
* @return
*/
public int nextInt() {
return id.incrementAndGet();
}
}
总结
- 缺点是项目启动时,会进行单例类的初始化操作,比较耗费资源
- 优点是:在项目启动时,即可发现问题
懒汉式
- 支持懒加载,在需要时使用加载
双重检测
目的是为了减少锁的粒度
/***
* 私有化构造方法
*/
private IdGenerator1() {
if (instance == null) {
synchronized (IdGenerator1.class) {
if (instance == null) {
instance = new IdGenerator1();
}
}
}
}
- 这种实现方式有些问题。因为指令重排序,可能会导致 IdGenerator 对象被new 出来,并且赋值给 instance 之后,还没来得及初始化(执行构造函数中的代码逻辑),就被另一个线程使用了。
- 给单例对象添加volatile关键字,禁用指令重排序
静态内部类
static class SingletonHolder {
public static IdGenerator2 instance = new IdGenerator2();
}
- SingletonHolder 是一个静态内部类,当外部类 IdGenerator 被加载的时候,并不会创建SingletonHolder 实例对象。只有当调用 getInstance() 方法时,SingletonHolder 才会被加载,这个时候才会创建 instance。insance 的唯一性、创建过程的线程安全性,都由JVM 来保证。所以,这种实现方法既保证了线程安全,又能做到延迟加载。
枚举
/**
* id生成器,需要设计为单例,双重检测
*/
public enum IdGenerator3 {
/**
* id生成器
*/
INSTANCE;
private AtomicInteger id = new AtomicInteger(0);
public int nextInt() {
return id.getAndIncrement();
}
}
- 从java语言的层面上,保证了线程安全与实例的唯一性
下一篇: 后端也要进行测试?