请解释双重检查锁定(Double-Checked Locking)单例模式,说明其核心作用,并比较它与饿汉式、懒汉式、静态内部类等单例实现方式的差异。
考察说明
考查对多线程下单例模式线程安全实现机制的理解及不同实现方式的权衡。
回答思路
- 【回答框架 1】双重检查锁定单例是一种延迟初始化单例,使用volatile修饰实例变量并同步代码块,先检查实例是否为空,为空才加锁,加锁后再检查一次,确保只创建一次实例。volatile防止指令重排导致返回未完全初始化的对象。
- 【回答框架 2】核心作用是兼顾线程安全与性能:相比懒汉式同步方法,双检锁只在首次创建时加锁,后续访问无锁竞争,减少同步开销,同时保证延迟加载。
- 【回答框架 3】与饿汉式相比,双检锁支持延迟初始化,饿汉式类加载即创建实例,启动快但占用资源;与静态内部类相比,静态内部类利用类加载机制天然线程安全且延迟加载,更简洁;与枚举单例相比,枚举天然防反射和防序列化破坏。
- 【回答框架 4】双检锁的缺点是代码复杂,依赖volatile的正确使用,在低版本Java或某些语言中需注意内存模型差异,易出错。
- 【关键点 1】双检锁必须使用volatile修饰实例变量,否则可能因指令重排返回未初始化对象。
- 【关键点 2】双检锁与普通懒汉式的区别在于锁粒度更细,性能更优。
- 【关键点 3】静态内部类单例比双检锁更简洁且无线程安全问题。
- 【关键点 4】饿汉式简单但无延迟加载,枚举单例最安全但不够灵活。
- 【易错点 1】忘记volatile关键字导致对象引用可见性问题。
- 【易错点 2】使用synchronized方法而非代码块,失去性能优势。
- 【易错点 3】在非Java语言中内存模型支持不同,双检锁可能无效。