java 禁止延迟加载_java 线程安全且延迟加载的单例模式

本文探讨了双重检查锁定在多线程环境中的问题,由于指令重排序可能导致未初始化的对象被访问。解决方案包括使用volatile关键字和依赖类初始化的延迟初始化。这两种方法分别适用于实例字段和静态字段的线程安全初始化,以实现性能和安全性之间的平衡。
摘要由CSDN通过智能技术生成

一 错误的用双重检查锁定

public class DoubleCheckedLocking { // 1

private static Instance instance; // 2

public static Instance getInstance() { // 3

if (instance == null) { // 4:第一次检查

synchronized (DoubleCheckedLocking.class) { // 5:加锁

if (instance == null) // 6:第二次检查

instance = new Instance(); // 7:问题的根源出在这里

} // 8

} // 9

return instance; // 10

} // 11

}

错误原因:第7行创建对象,可以分解为三步,分别为分配内存、初始化对象、引用指向内存地址,后两步可能存在重排序,导致访问到未初始化的成员

解决方法:1)不允许重排序。2)允许重排序,但不允许其他线程“看到”这个重排序。

二 基于volatile的解决方案,禁止重排序

用volatile修饰instance。

三 基于类初始化的解决方案

JVM在类的初始化阶段(即在Class被加载后,且被线程使用之前),会执行类的初始化。在

执行类的初始化期间,JVM会去获取一个锁。这个锁可以同步多个线程对同一个类的初始化。

public class InstanceFactory {

private static class InstanceHolder {

public static Instance instance = new Instance();

}

public static Instance getInstance() {

return InstanceHolder.instance ;  // 这里将导致InstanceHolder类被初始化

}

}

四 综述

字段延迟初始化降低了初始化类或创建实例的开销,但增加了访问被延迟初始化的字段

的开销。在大多数时候,正常的初始化要优于延迟初始化。如果确实需要对实例字段使用线程

安全的延迟初始化,请使用上面介绍的基于volatile的延迟初始化的方案;如果确实需要对静

态字段使用线程安全的延迟初始化,请使用上面介绍的基于类初始化的方案。

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值