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关键字回顾之线程可见性的主要内容,如果未能解决你的问题,请参考以下文章