11-volatile:synchronized的轻量级实现

本文深入解析了Java中Volatile关键字的作用机制,包括其如何保证内存可见性和禁止指令重排序,探讨了Volatile与Synchronized及CAS结合的使用场景,以及在多线程环境下对变量操作的影响。
    1. 作用:保证数据的可见性,以及确保变量不会被重排序

volatile关键字修饰的成员变量,不存在工作线程的副本;每次直接都从主内存中读取。只能保证数据的可见性,但不保证操作的原子性。

    1. 内存可见性

写一个volatile变量时,JMM首先修改工作内存中的变量值,并刷新到主内存中。

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

对volatile变量的读写,可以说都是直接对主内存进行的操作,这样虽然会牺牲一些性能,但是解决了“缓存一致性问题”,使得变量在多线程间的可见性得到了很好的保证。

 

    1. 禁止指令重排序-内存屏障

Singleton instance= new Singleton();

编译出的字节码指令可以用如下三行表示:

    1.为对象分配内存空间2.初始化对象 3.将INSTANCE变量指向刚分配的内存地址

由于步骤2,3交换不会改变单线程环境下的执行结果,故而这种重排序是被允许的。

故在多线程下可能存在获取的instance==null的情况

instance变量加个volatile关键字,这样编译器就会根据一定的规则禁止对volatile变量的读写操作重排序。而编译出的字节码,也会在合适的地方插入内存屏障,比如volatile写操作之前和之后会分别插入一个StoreStore屏障和StoreLoad屏障,禁止CPU对指令的重排序越过这些屏障。

    1. 变量的读写,操作的读写

对volatile变量的读写具有原子性,但是其他操作并不一定具有原子性,一个简单的例子就是i++。由于该操作并不具有原子性,故而即使该变量被volatile修饰,多线程环境下也不能保证线程安全。

    1. 使用案例
      1. 和Synchronized结合,用于对变量n读多写少的情况

告诉处理器, 不要将我放入工作内存, 请直接在主存操作我。

      1. 和CAS结合保证操作的原子性,如AtomicInteger

 

      1. 修饰线程之间的共享变量

如下图程序,运行时会一直卡在循环中。即子线程中修改主存后,但是main线程读取的是当前线程存储空间的值,导致循环不能停止。添加volatile修饰后,在子线程运行结束后,主线程会退出循环。

    1. 注意事项:本身不具备线程安全的特性

多线程学习大纲:https://mp.youkuaiyun.com/postedit/84768644

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值