单例设计模式(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语言的层面上,保证了线程安全与实例的唯一性