当前位置:网站首页>voliate关键字
voliate关键字
2022-08-03 03:18:00 【lzhNox】
voliate关键字详解:
1.内存模型相关概念
物理计算机内存访问图:
任何计算都是在CPU内处理的,那么也就必须涉及到数据读写,但是CPU每次都要和主内存交互读写数据效率太低了,于是有了高速缓存。在程序运行时,会从主内存中复制一份数据到高速缓存中,然后CPU在高速缓存中读写数据,计算完成后,再将结果从高速缓存中返回到主内存里。
在单线程中,上述操作是不会有问题的,但在多线程中就不行了
例如我们让两个线程都进行a=a+1
的操作,按常理来说,结果会是2,但是有一下一种情况:
线程1和线程2都从主内存中读数据到高速缓存中,此时他们读的都是a一开始等于0的情况,然后分别在CPU中运算,线程1完成后,将结果a=1返回到主内存中。线程2完成运算后从高速内存将结果返回,还是a=1。那么结果就是两个线程分别做了加一运算,但是结果为1。
也就是说,一个变量在多个CPU中都有缓存就会出现:缓存不一致问题
2.Java内存模型
JMM(Java Memory Model)图:
工作内存其实是缓存、寄存器、编译器优化等笼统概念。
Java内存模型规定所有的变量都是存在主存当中(类似于前面说的物理内存),每个线程都有自己的工作内存(类似于前面的高速缓存)。线程对变量的所有操作都必须在工作内存中进行,而不能直接对主存进行操作。并且每个线程不能访问其他线程的工作内存。
这个图可以和物理计算机内存图类比,也会存在缓存不一致问题,并且Java中没有限制编译器为了提高效率对指令进行重排序,所以也会出现指令重排序问题
2.voliate关键字作用
为了解决Java缓存不一致和重排序问题,于是有了voliate关键字。
当一个共享变量被voliate修饰后
- 保证了这个变量再不同线程的可见性,一个线程修改了它,另一个线程立马知道
- 禁止指令重排序
前面说了,CPU会在缓存中读写数据,那么加了voliate关键字之后:
- 会将结果值立马写入主存
- 使其他线程对应变量的缓存无效,所以需要再次去主存中读取
我们用一段代码理解一下:
static class Counter {
public int flag = 0;
}
public static void main(String[] args) {
Counter counter = new Counter();
Thread t1 = new Thread(() -> {
while (counter.flag == 0) {
// do nothing
}
System.out.println("循环结束!");
});
Thread t2 = new Thread(() -> {
Scanner scanner = new Scanner(System.in);
System.out.println("输入一个整数:");
counter.flag = scanner.nextInt();
});
t1.start();
t2.start();
}
t1线程会一直循环,t2线程会让用户输入一个整数,当用户输入0以外的值时,欲使t1线程循环结束。
但是执行结果是:输入5,t1线程仍在循环。
原因就是我们刚才所说的,t1线程一直读取的是工作内存的数据,工作内存中的flag任然是0,它没有意识到主存中flag的值已经为5了。
那么我们给flag用以voliate关键字修饰之后,就不会出现问题了。t2线程修改了flag值后会马上写入主存,t1线程工作内存的flag缓存会马上作废,从主存中读取flag的新值。
voliate不能保证原子性,它保证了内寸可见性和一定程度上的有序性
一定程度上的有序性是什么意思?
就是说加了voliate修饰的变量,对它的值进行修改的代码行相对位置不会变,不会受到指令重排序的影响
比如:
a,b,c,d没有被voliate关键字修饰
flag被voliate关键字修饰了
a=1;
b=2;
flag=5;
c=4;
d=6;
那么flag的位置一定会在a,b和c,d之间夹着。但是a,b的顺序可能调换,c,d的顺序也可能调换,所以是一定程度上的有序性。
边栏推荐
猜你喜欢
随机推荐
shell之条件语句(条件测试、if语句,case语句)
Summary of some questions about the grain mall
C语言实验十二 指针(二)
谷粒商城一些疑问总结
机器学习【KNN案例、API、总结】
基于flowable的upp(统一流程平台)运行性能优化(3)
第三方支付--分账对接
leetcode:152. 乘积最大子数组
【GraphQL】使用Hot Chocolate和.NET 6构建GraphQL应用
DPDK mlx5 驱动使用报错
MySQL-多表查询
利用索引机制进行绕过
记录学习--Navicat使用自定义数据库列表
# RACE32——高级断点的设置和应用
ClickHouse卸载、重安装
Pro_07丨波动率因子3.0与斜率因子
js Fetch返回数据res.json()报错问题
leetcode:172. 阶乘后的零
Nacos入门学习
PyTorch installation - error when building a virtual environment in conda before installing PyTorch