Java并发编程 - 实现可见性

1、volatile

    通过内存屏障和禁止指令重排序来保证可见性的。

       (a)、对volatile进行读操作,会在读操作之前增加一个load屏障指令

       (b)、对volatile进行写操作,会在写操作之后增加一个store屏障指令

    内存屏障:处理器的一组指令,用于实现对内存操作的顺序限制(指令重排时不能把后面的指令重排列到内存屏障之前的位置)

2、synchronized

    同步块的可见性是由:对一个变量执行unlock操作之前,必须把此变量同步回主内存中(执行store、write操作)

3、final

    其可见性是指:被final修饰的字段在构造器中一旦初始化完成,并且构造器没有把“this”的引用传递出去(this引用逃逸是一件很危险的事情,其它线程有可能通过这个引用访问到“初始化了一半”的对象),那在其他线程中就能看见final字段的值。如下程序所示,变量i和j都具备可见性,他们无须同步就能被其他线程正确访问。

实现内存可见性的两种方法比较:synchronized 和 Volatile

在《synchronized 的另个一重要作用:内存可见性》这篇文中,讲述了通过同步实现内存可见性的方法,在《Volatile 关键字(上)》这篇文中,讲述了通过 volatile 变量实现内存可见性的方法,这里比较下二者的区别。

  • volatile 变量是一种稍弱的同步机制在访问 volatile 变量时不会执行加锁操作,因此也就不会使执行线程阻塞,因此 volatile 变量是一种比 synchronized 关键字更轻量级的同步机制。
  • 从内存可见性的角度看,写入 volatile 变量相当于退出同步代码块,而读取 volatile 变量相当于进入同步代码块。
  • 在代码中如果过度依赖 volatile 变量来控制状态的可见性,通常会比使用锁的代码更脆弱,也更难以理解。仅当 volatile 变量能简化代码的实现以及对同步策略的验证时,才应该使用它。一般来说,用同步机制会更安全些。
  • 加锁机制(即同步机制)既可以确保可见性又可以确保原子性,而 volatile 变量只能确保可见性,原因是声明为 volatile 的简单变量如果当前值与该变量以前的值相关,那么 volatile 关键字不起作用,也就是说如下的表达式都不是原子操作:count++count = count+1

当且仅当满足以下所有条件时,才应该使用 volatile 变量:

  • 对变量的写入操作不依赖变量的当前值,或者你能确保只有单个线程更新变量的值。
  • 该变量没有包含在具有其他变量的不变式中。

总结:在需要同步的时候,第一选择应该是 synchronized 关键字,这是最安全的方式,尝试其他任何方式都是有风险的。尤其在、jdK1.5 之后,对 synchronized 同步机制做了很多优化,如:自适应的自旋锁、锁粗化、锁消除、轻量级锁等,使得它的性能明显有了很大的提升

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值