volatile轻量级锁

一、背景

我们在写项目的时候,有时会使用多线程。为了保证一部分线程之间的通信,所以需要线程中的一些变量具有可见性。

说到线程可见性,对于Java而言,有两种方法实现:volatile和synchronized。

需要注意的是:volatile只用来保证该变量对所有线程的可见性,但不保证原子性。

虽然加锁同样能解决共享变量不可见性的问题,但是加锁和锁的释放过程都是会有性能消耗的,所以在解决共享变量不可见性的问题时,我们首选 volatile关键字

二、作用

volatile是Java提供的轻量级的同步机制,保证了可见性,不保证原子性。要了解volatile工作机制,首先要对Java内存模型(JMM)有初步的认识:

  • 每个线程创建时,JVM会为其创建一份私有的工作内存(栈空间),不同线程的工作内存之间不能直接互相访问。JMM规定所有的变量都存在主内存,主内存是共享内存区域,所有线程都可以访问
  • 线程对变量进行读写,会从主内存拷贝一份副本到自己的工作内存,操作完毕后刷新到主内存。所以,线程间的通信要通过主内存来实现。

 volatile的作用是:线程对副本变量进行修改后,其他线程能够立刻同步刷新最新的数值,这个就是可见性。同时还有禁止指令重排。

三、原理

volatile的内存语义

内存语义可以理解为 volatile 在执行计算时,内存中的要实现的功能与规则:

  • 一个 volatile 变量时,JMM 会把该线程对应的本地内存中的共享变量值刷新到主内存。
  • 一个 volatile 变量时,JMM 会把该线程对应的本地内存置为无效,并从主内存中读取共享变量。

 四、volatile 与 static

  • static 修饰的变量:多实例间,保证变量的唯一性。但是没有可见性和原子性的保证。
  • volatile 修饰的变量:多实例间,变量没有唯一性。但是能保证线程可见性,不保证原子性。

所以,static volatile 修饰的变量就是多实例间的唯一性,以及线程间的可见性。

五、总结

  • 适用场景:某个属性被多个线程共享,其中有一个线程修改了此属性,其他线程可以立即得到修改后的值,比如 booleanflag;或者作为触发器,实现轻量级同步。
  • volatile 变量的读写操作都是无锁的,低成本的。它不能替代 synchronized,因为它没有提供原子性和互斥性。
  • volatile 只能作用于属性,我们用volatile修饰属性,这样compilers就不会对这个属性做指令重排序。
  • volatile 可以在单例双重检查中(特殊场景)实现可见性和禁止指令重排序,从而保证安全性。

线程可见、禁止指令重排、不一定有原子性。

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

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

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

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值