JavaSE 多线程 数据结构
本篇文章针对于volatile保证内存可见性进行了一个详细的讲解,而指令重排序将在单例模式中进行讲解,本篇文章也是干货满满!!!
Volatile 修饰的变量能够保证“内存可见性”以及防止”指令重排序“
什么是可见性:当某个线程修改了某个共享变量,其他的线程是否可以看见修改后的内容;
因为访问一个变量时,CPU就会先把变量从内存中读出来,然后放到CPU寄存器中进行运算;运算完之后,再将新的数据在内存中进行刷新;
对于操作系统来讲,读内存的速度是非常慢的,(注意:这里的慢 是 相对于寄存器而言的,就像,读内存要比读硬盘快上千倍或上万倍,读寄存器比读内存快上千倍上万倍), 这时候就会影响执行的效率。
为了提高效率,编译器就会对代码进行一个优化,把读内存的操作优化成读寄存器,从而减少对内存的读取,提高整个效率;
举个例子:
代码目的:创建两个线程,通过线程2修改线程1的循环判断条件来终止线程1的循环执行
public class Demo1 {
private static int flag = 0;
public static void main(String[] args) {
Thread thread1 = new Thread(() -> {
while(flag == 0) {
//当循环不等于0时,一直循环,直到flag被改变
}
System.out.println("thread1 执行结束");
});
Thread thread2 = new Thread(() -> {
Scanner in = new Scanner(System.in);
System.out.println("更改flag:");
//通过更改flag终止线程1的执行
flag = in.nextInt();
System.out.println("输入成功");
});
thread1.start();
thread2.start();
}
}
根据结果可以看到,线程1并没有终止循环,这就是“内存可见性”所导致的线程不安全
在多线程的环境下(在单线程环境下没问题),如果编译器作出优化,可能就会导致,虽然提高了效率,但是最后结果却是错误的,
此时就需要程序员使用Volatile关键字告诉编译器,不需要进行代码优化:
直接给flag加上Volatile即可
注意, volatile只能够保证内存可见性问题,不会保证代码的原子性,但是Synchronized既可以保证内存可见性,也能保证原子性;
以上就是volatile能够保证内存可见性的讲解,关于volatile能够防止指令重排序将在单例模式中进行讲解单例模式