(七)java并发编程synchronized+volatile(安全初始化模式实例)

安全发布对象的安全性都来自于JMM提供的保证,而造成不正确的发布原因,就是在”发布一个共享对象”与”另一个线程访问该对象”之间缺少一种Happen-Before排序.

不安全的发布

package safe_unsafe_publication;
/**
 * Created by fang on 2017/11/24.
 * 不安全发布,一个线程正在初始化,另一个线程可能读到未构造完全的对象.
 */
public class UnsafeLazyInitialization {
   
    private static Resource resource;

    public static Resource getInstance(){
        if(resource == null){
            resource = new Resource();
        }
        return resource;
    }
}

上述代码中的不安全性有两个方面
1 资源竞争问题
类的静态变量存在方法区,resource类变量(“地址变量”),被线程A 和线程B共享,但是当线程A写入resource地址变量值的时候,可能在cpu寄存器(cpu高速缓存)还未同步到cpu主存中(每一个线程都有自己的cpu高速缓存,在高速缓存中互相看不到).

导致线程B在判断resource仍然为null,线程B可能也会new Resource()操作. 这就导致了资源的竞争,也就是(查看–修改–写入)并非是原子性操作.

2 类的实例对象构造不完整,或构造错误问题.
线程A在实行getInstance()方法的时候,发现resource为null,然后new Resource(),然后设置为指向resource.
然后线程B在判断resource是否为null时,假设此时线程A中的类变量resource已经同步到CPU主存,B发现类变量resource并不为null,然后就获取resource地址,直接使用线程A new出来的对象.
.B可能使用A创建的Resource对象并不完整,或者创建时错误的.(线程B看到A线程的执行顺序,和A真正的执行顺序可能不同,JVM重排列).

(以上是自己的理解,与类的加载过程有关系,在加载 连接阶段已经有了类的地址变量,但下一个阶段才是对象的初始化阶段. 也就是在方法区已经存在对象实例的地址对象变量,但是堆中的实例对象并没有初始化完整.)

官方说明:

除了不可变对象外,使用被另一个线程初始化的对象通常是不安全的,除非对象的发布操作是在使用该对象的线程开始使用之前执行.

安全发布

安全初始化模式

如下代码

 package safe_unsafe_publication;


 /**
  * Created by fang on 2017/11/24.
  * 安全的延迟加载
  */
 public class SafeL
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值