当前位置:网站首页>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的顺序也可能调换,所以是一定程度上的有序性。
边栏推荐
猜你喜欢
随机推荐
Best Practices for Migration from Jincang Database from MySQL to KingbaseES (3. MySQL Database Migration Practice)
【GraphQL】使用Hot Chocolate和.NET 6构建GraphQL应用
单元测试是什么?怎么写?主要测试什么?
ClickHouse卸载、重安装
信号和槽的绑定
C语言实验十一 指针(一)
在VScode里调试ROS程序
Auto.js Pro 编写第一个脚本hello world
HCIP第十八天
els 计分
Pro * C Jin Cang database migration guide (4) KingbaseES Pro * C migration guide)
一次偶然的钓鱼文件分析
问下有用sql server flink-sql-connector-sqlserver-cdc-2
工作两年成跳槽高峰期,程序员会在一家公司待多久?
金仓数据库 Pro*C 迁移指南( 5. 程序开发示例)
05-分布式计算框架
详细讲解一下JVM的内存模型与实现?
DPDK mlx5 驱动使用报错
Spark SQL简介
Jmeter TCP/UDP测试