JAVA并发编程:volatile关键字深入解析

生活

天气贼好的一个礼拜二。
生活就是生下来活下去。

简述

volatile是JAVA中的一个关键字,在JDK1.5以前据说饱受争议,在程序中使用经常出现一些出入意料的结果。

这个么,从volatile的翻译就能看出来,就是不稳定的意思嘛。

JDK1.5以后,volatile才重获生机。(我认为是Doug Lea写的并发包把它发扬光大了)。

学习它有什么用?

1、有助于内存模型的深入了解
2、有助于并发编程的深入学习
3、方便后期与synchronized关键字对比学习

特性

1、可见性
2、有序性(一定程序上保障有序性)

注意 没有原子性,所以单纯使用这个关键字,并不是线程安全的。需要搭配其他锁来保证线程安全。

使用

直接套用前面的场景

场景说明:
两个线程共享一个变量stop.
A线程,当stop为false,则一直运行;为true则停止。
B线程,设置stop为true

public class Test {
    static  boolean stop;

    public static void main(String[] args) throws InterruptedException {

        new Thread(new Runnable() {
            @Override
            public void run() {
                System.out.println("线程A运行中");
                while (!stop);
                System.out.println("线程A已停止");
            }
        }).start();

        Thread.sleep(10);


        new Thread(new Runnable() {
           @Override
           public void run() {
               System.out.println("线程B运行中");
               stop = true;
               System.out.println("stop设置为true,线程B已停止");
           }
       }).start();
    }
}

其中一次运行结果:
线程A运行中
线程B运行中
stop设置为true,线程B已停止

由此见得,一个普通的变量在多线程环境下不具有可见性。

扫描二维码关注公众号,回复: 4267331 查看本文章

只需要给stop变量加上关键字volatile,在多线程环境下就不会在出现不可见的情况。

PS:上面讲到volatile实现可见性,其实我认为这个可见性本身就是基于 一定程度的有序性实现的。即对volatile的变量读取之前,必须保证前面的更新已经刷入主内存。
这是通过内存屏障来禁止重排序实现了一定的有序性,从而达到可见性。

实现原理

关于volatile的实现原理,我看了很多博客,讲的很多,都是对的,但是讲的实在太多了,本来想把他们讲的东西抄下来,感觉意义不大。自己简单的分析一下:
1、为什么会出现不可见性的问题?
原因在于:多线程环境下存在工作内存和主内存,每个线程的工作内存都是独立的,在使用一个变量之前要先拷贝一份副本到自己的工作内存,更新一个变量,需要先在自己的工作内存中更新,在刷入到主内存。
不可见性出现的问题就在于A线程读取变量的时候,可能B线程更新了但是并没有刷入主内存。导致不一致的情况。

2、如果避免不可见性?
从现实角度分析,就必须强制要求在A线程读取变量之前其他线程的更新操作必须刷入主内存。也就是volatile的关键字语义,被volatile修饰的变量,被一个线程修改后可以及时被其他线程读取到。

3、如果实现2中提到的避免不可见性的操作。
两种办法:
3.1互斥锁:即多个线程访问使用同一个变量时,同一个时刻只由一个线程上锁操作访问这个变量,访问结束unlock()后其他线程才可以访问,强制实现了可见和有序。
3.2volatile:他的实现原理就是jvm内存模型中本身的内存屏障,在volatile写的后面加上store load 屏障,禁止volatile写与后面的操作重排序,即volatile写必须先于后面的操作。

总结反思

这是我理解的volatile,有不对和不恰当的烦请指正!

猜你喜欢

转载自blog.csdn.net/qq_28605513/article/details/84564494