欢迎您访问365答案网,请分享给你的朋友!
生活常识 学习资料

了解volatile

时间:2023-06-30

介绍:
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是不禁止指令重排的,它可以保证可见性是因为同一时间它只让同一个线程执行代码块,由于数据依赖性的存在,单线程的指令重排是没有问题
如有错误请指出谢谢

Copyright © 2016-2020 www.365daan.com All Rights Reserved. 365答案网 版权所有 备案号:

部分内容来自互联网,版权归原作者所有,如有冒犯请联系我们,我们将在三个工作时内妥善处理。