了解volatile

介绍:
volatile是Java中的一个轻量级同步机制,主要有三个特性,1,可见性,2,有序性,3,不保证原子性
可见性
在介绍可见性我还得介绍另一个东西,JMM。这是一个规范,他描述了获取变量的一些规范,屏蔽各种硬件和操作系统的内存访问差异,实现让 Java 程序在各种平台下都能达到一致的内存访问效果规定了线程和内存之间的一些关系。JMM里面规定,线程共享的变量存储在主内存中,每个线程有自己的一个工作内存,每次都是先把主内存中的数据拷贝到自己的工作内存进行操作,然在写入主内存
在这里插入图片描述
这就引发一件事,数据不一致性,当线程A把数据拷贝到了自己工作内存中,在自己工作内存中重新修改了该值,但是还没有写回主内存的时候,线程B就从主内存读取了旧的值,这就是不一致性。可见性就是解决这个问题,一个线程修改了某一变量值,其他的线程都能看到。
使用volatile修饰的变量,底层会开启总线嗅探机制,实现MESI协议来保证缓存一致性的问题,来保持可见性
有序性:
当我们写如下一行代码

public void mySort() {
     int x = 11; //语句1
     int y = 12; //语句2  谁先执行效果一样
     x = x + 5;  //语句3
     y = x * x;  //语句4
}

执行顺序是:1 2 3 4、2 1 3 4、1 3 2 4
我们看到执行的顺序并不一定按照我们写代码的顺序来执行,有与JVM编译器的优化,执行的顺序会有差别,这叫指令重排
但是指令重排也是有一定的要求的,他是有一定的依赖性的,语句4是依赖于前面得到的值,才能计算,所以不能排在前面。当我们用用volatile修饰变量的时候,会在底层调用lock前缀指令,会加上相应的内存屏障。
内存屏障分为两种:
写屏障:屏障会确保指令重排序时,不会将写屏障之前的代码排在写屏障之后
读屏障:读屏障会确保指令重排序时,不会将读屏障之后的代码排在读屏障之前
当一个线程发生指令重排的时候,由于数据依赖性的存在,单线程的指令重排是没有问题,而多线程就无法保证了,会发生指令交错。volatile修饰的变量他是禁止指令重排的。
不保证原子性
原子性是一个代码块,或者一个业务,要么里面的操作同时成功,要么同时失败,而volatile不保证原子性,synchronized是保证原子性,有序性,可见性的。
synchronized是不禁止指令重排的,它可以保证可见性是因为同一时间它只让同一个线程执行代码块,由于数据依赖性的存在,单线程的指令重排是没有问题
如有错误请指出谢谢

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值