【面时莫慌】你好,请谈谈volatile关键字?(一)

这是我参与更文挑战的第24天,活动详情查看: 更文挑战

说起Volatile关键字,很多人那叫一个气,这个不起眼的Java关键字为难了太多的英雄好汉。初看它时,觉得格外的简单,仔细看它,才发现打扰了。这篇文章带大家由深及浅的分析这个关键字。

一、灵魂拷问

那一年,在某个你想去奋斗的地方,你可曾被问到以下的问题。

  • volatile是什么,它与synchronized的区别?你在什么地方看到过,用到过?
  • 哪些场景下适合使用Volatile
  • volatile是为了解决什么问题?它的优缺点是什么?
  • 谈谈volatile底层原理?再说说MESI吧?
  • 你知道happen-before原则吗?

COMBO连击,完全招架不住,我是谁?我为什么在这?时候不早了,我是不是该回去休息了。

二、实例分析

我们先以实例走进这个关键字。

/**
     * thread safely
     */
    //public static volatile  boolean run = true;
    /**
     * thread not safely
     */
    public static  boolean run = true;

    public static void main(String[] args) throws InterruptedException {
        new Thread(()->{
            int i=0;
            while (run){
                i++;
                Thread.yield();
                System.out.println(i+" loading...");
            }
        }).start();
        System.out.println("Main Thread ready to sleep...");
        TimeUnit.SECONDS.sleep(10);
        System.out.println("Main Thread finish sleep...");
        run= false;
    }
复制代码

以上的例子演示了使用Volatile关键字和不使用的区别。

#线程不安全
public static  boolean run = true;
复制代码

使用线程不安全的写法,结果表明,会存在相当小的概率让子线程一直处于RUNNABLE的状态,永远停下来。需要注意的是,真的概率非常的小,我运行了上万次,才能出现一次子线程无法停下来。但也就这一次可能就会引发一次严重的生产事故。

#线程安全
public static volatile  boolean run = true;
复制代码

上面的代码是线程安全的,可以从根本上解决死循环的问题。那么为什么呢?

先简单的解释一下,核心问题就是虽然主线程修改了值,子线程并没有感知到主线程修改run变量为false。Why,后面看我细细分析。

三、什么是volatile

volatile关键字用于多线程修改同一变量值的场景,它使线程能安全的访问、操作共享变量。这意味着多个线程能同时使用一个方法和实例,而不会出任何问题。这个关键字既能修饰Java的基本类型,也能修改引用类型。

上面的描述都是在说现象,真正的底层原理是,基于JMM( Java Memory Model),volatile 关键字用于将 Java 变量标记为“存储在主内存中”。更加准备地说,每一次 volatile变量的读取都将从计算机的主存中读取,而不是从CPU高速缓存中读取,每一次写入 volatile变量将被写入主存中,而不仅仅是写入 CPU 缓存中。

众所周知,当多个线程要同时访问共享变量的时,需要考虑三个方面,包括原子性、可见性、顺序性。原子性代表当另一个线程对共享数据执行某些操作时,不应该有线程干扰;可见性代表行为对线程共享数据的影响应该可以被其他线程感知到;顺序性代表指令执行顺序应该与源代码中表达的顺序相同。

分析volatile,它具有:

  • 可见性,对一个volatile变量的读,总是能看到(任意线程)对这个volatile变量最后的写入。
  • 原子性,对任意单个volatile变量的读/写具有原子性。但是对于i++这种复合操作不具有原子性。
  • 顺序性,volatile关键字能禁止指令重排序,所以volatile能在一定程度上保证有序性.。
© 版权声明
THE END
喜欢就支持一下吧
点赞0 分享