volatitle关键字

  volattile关键字只能修饰变量,无法用于修饰方法。并且volatitle可以避免重排序和内存可见性问题,但不能保证原子性。

  使用锁的方式可以解决共享变量的内存可见性问题,但是使用锁太笨重,因为它会带来线程上下文的切换开销。对于解决内存可见性问题,Java还提供了一种弱形式的同步,也就是使用synchronized关键字。

  该关键字可以确保对一个变量的更新对其他线程马上可见。当一个变量被声明为volatitle时,线程在写入变量时不会把值缓存在寄存器或其他地方,而是会把值刷新回主内存。当其他线程读取该共享变量时会从主内存重新获取最新值,而不是使用当前线程的工作内存中的值。

volatitle工作原理

为什么volatitle可以保证内存可见性,而不能保证原子性?这与它的工作原理有关。

  • 线程写volatitle变量步骤为:

    • 改变线程工作内存中volatitle变量副本的值

    • 将改变后的副本的值从工作内存刷新到主存

  • 线程读volatitle变量步骤为:

    • 从主内存读取volatitle变量的最新值到线程的工作内存中
    • 从工作内存中读取volatitle变量的副本

   由于整个过程没有涉及到锁相关操作,所以无法保证原子性;但是由于实时刷新了主内存中的变量值,因此任何时刻,不同线程总能看到该变量的最新值,保证了可见性。

Java中的CAS操作

  在Java中,锁在并发处理中占据了一席,但是使用锁有一个不好的地方,就是一个线程没有获取到锁时会被阻塞挂起,这会导致线程上下文的切换和重新调度开销。Java提供了非阻塞的valotitle关键字来解决共享变量的可见性问题,这在一定程度上弥补了锁带来的开销问题,但是volatitle只能保证共享变量的可见性,不能解决读——改——写等的原子性问题。
CAS即Compare and Swap,其是JDK提供的非阻塞原子性操作,它通过硬件保证了比较——更新操作的原子性。但是要清楚CAS只是比较和交换,在获取原值的这个操作上,需要你自己实现。
但CAS也存在三大问题:
1.ABA问题:
  关于CAS操作有个经典的ABA问题,当变量的值发生了环型变换,CAS操作并不能识别这一情况。JDK中的AtomicStampedReference类给每个变量的状态值都配备了一个时间戳,从而避免了ABA问题的发生。
2.循环时间长开销大
如果多个线程同时对一个共享变量进行CAS操作,那么只有一个线程能够成功,会造成大量线程进行自旋重试,这会降低并发性能
3.只能保证一个变量的原子操作
CAS只能保证一个共享变量的原子操作,如果需要对多个共享变量进行原子操作,需要使用其他技术,如锁或原子类。

volatitle使用场景

要在多线程中安全的使用volatitle,必须同时满足

  • 对变量的设置操作不依赖于当前值
    • 不满足举例:number++、count = count + 5
    • 满足举例: boolean 变量等
  • 该变量不能和其他变量一起参与判断
    • 不满足举例:不变时 low < up
    • 不满足举例:if(a && b)

在实际项目中,由于很多情况下都不满意 volatile 的使用条件,所以 volatile 使用的场景并没有 synchronized 广。

  • 5
    点赞
  • 7
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值