Volatile关键字回顾之线程可见性

Posted nysd

tags:

篇首语:本文由小常识网(cha138.com)小编为大家整理,主要介绍了Volatile关键字回顾之线程可见性相关的知识,希望对你有一定的参考价值。

java中,volatile关键字有两大作用:

  1.保证线程的可见性

  2.防止指令重排序

这篇文章主要通过典型案例,体现可见性这一特性。

概念:

  java中,堆内存是线程共享的。而每个线程,都应该有自己独享的内存用于工作。所以,当线程访问到堆内存中的共享变量时,会考虑copy一份,存在自己的工作空间中。之后对工作空间中的值进行操作,完成后重新写回到堆内存。

  这样一来,在多线程同时访问这个变量时,就可能出现拿不到实时的值的问题(根本原因在于:本来共享的变量,因为缓存到各个线程的工作空间导致数据在写回之前不互通)。

  而volatile的作用之一,就是解决这一问题。

下面通过一段代码,来展示volatile的这一特性。

 1 public class HelloVolatile {
 2     private volatile boolean running = true; //开关,表示是否可运行
 3 
 4     void m(){
 5         System.out.println("m start");
 6         //一直执行
 7         while(running){
 8 
 9         }
10         //如果running一直未true,下面的代码执行不到
11         System.out.println("m end");
12     }
13 
14     public static void main(String[] args) {
15         HelloVolatile helloVolatile = new HelloVolatile();
16         //新建线程,run方法调用m方法,running为true时一直循环
17         new Thread(helloVolatile::m, "非主线程").start();
18         //休眠1s
19         try {
20             TimeUnit.SECONDS.sleep(2);
21         } catch (InterruptedException e) {
22             e.printStackTrace();
23         }
24         //主线程设置running为false,如果running不加volatile,则新建的线程是读不到的
25         helloVolatile.running = false;
26     }
27 }

running变量不加volatile的执行结果:

m start

加了volatile的执行结果:

m start
m end

可见性的原理:

MESI(缓存一致性)协议:

  1.写数据时,如果发现操作的是共享变量,会发出信号通知其他CPU设置该变量的缓存行为无效状态。

  2.当其他CPU使用这个变量时,会先去观察是否有更改的信号,当发现缓存行失效时,会从主内存(堆中)重新读取此变量。
volatile的优缺点:

  优点:高效(非锁机制)

  缺点:仅仅保证可见性,不保证数据的一致性。

以上是关于Volatile关键字回顾之线程可见性的主要内容,如果未能解决你的问题,请参考以下文章

第234天学习打卡(知识点回顾volatile 2 CAS)

Java并发编程之volatile

java并发编程之volatile关键字

Java——多线程高并发系列之volatile关键字

Java——多线程高并发系列之volatile关键字

volatile可见性和指令重排