<多线程章节六>如何保证内存可见性和防止指令重排序,以及volatile的使用方法

专栏导读

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();
    }
}

<多线程章节六>如何保证内存可见性和防止指令重排序,以及volatile的使用方法_第1张图片

根据结果可以看到,线程1并没有终止循环,这就是“内存可见性”所导致的线程不安全

<多线程章节六>如何保证内存可见性和防止指令重排序,以及volatile的使用方法_第2张图片

在多线程的环境下(在单线程环境下没问题),如果编译器作出优化,可能就会导致,虽然提高了效率,但是最后结果却是错误的,

此时就需要程序员使用Volatile关键字告诉编译器,不需要进行代码优化:

直接给flag加上Volatile即可

<多线程章节六>如何保证内存可见性和防止指令重排序,以及volatile的使用方法_第3张图片

注意, volatile只能够保证内存可见性问题,不会保证代码的原子性,但是Synchronized既可以保证内存可见性,也能保证原子性;

以上就是volatile能够保证内存可见性的讲解,关于volatile能够防止指令重排序将在单例模式中进行讲解单例模式

你可能感兴趣的:(多线程,javascript,开发语言,ecmascript)