博客
关于我
强烈建议你试试无所不能的chatGPT,快点击我
Java中的关键字--volatile
阅读量:4517 次
发布时间:2019-06-08

本文共 1655 字,大约阅读时间需要 5 分钟。

  volatile关键字经常用来修饰变量。不过,volatile本身很容易被误用。本篇就介绍一下volatile的原理和使用方式。

  在介绍volatile关键字原理前,我们首先要了解JVM运行时的内存分配逻辑。

  

  对于成员变量i,它存储在堆内存中。每个线程在运行时都会有一个自己的线程栈,线程如果要访问类的成员变量i,会通过引用获取到堆中变量i实际的值10,然后把这个变量值拷贝到自己的栈内存中,作为一个变量副本,之后线程便不再会与堆中的变量有实际联系。每个线程都有一个自己的本地副本,相互隔离。线程访问自己栈内存的效率比访问堆的效率高。线程对变量i值的修改,只会修改自己线程副本中的值,修改结束后,在线程退出前,会把自己线程副本中的值,刷新到堆中。

保证内存可见性

  对于如下代码:

public class VolatileTest implements Runnable{
  //volatile private static boolean flag = false; @Override public void run() { while (!flag){ System.out.println(Thread.currentThread().getName() +"执行中"); } System.out.println(Thread.currentThread().getName() +"执行完毕"); } //main线程 public static void main(String[] args) throws InterruptedException { new Thread(new VolatileTest(), "支线程Volatile").start(); Thread.sleep(1000); flag = true; }}

  大多数时候可以正常中断,但是一旦发送异常,便会导致线程死循环。所以需要在flag标志上加一个volatile关键字。对于加了volatile关键字的变量值,线程1修改了这个值的话,会强制将修改值直接写入堆内存中,其他线程各自线程栈中的变量副本无效,只能去堆中取最新的变量值。多个线程之间的内存可见得以保证。

  值得注意的是,volatile关键字不能保证原子性。

  

private volatile int i;i++;

  i ++ 这个操作涉及到获取值,自增和赋值3部分。无法直接完成。上面想要以volatile来实现原子性的写法是错误的。

禁止指令重排

  现代JVM对代码的执行顺序有一定的优化。例如:

int a = 4;int b = 5;int c = a + b;

  上面3条指令进过JVM优化以后,时间的执行顺序不一定是从上到下,有可能是 第二条--->第一条-->第三条。总之不会影响最终执行结果。

  但是在多线程情况下,如下代码就会有风险:

//线程1:context = loadContext();   inited = true;              //线程2:while(!inited ){  }doSomething(context);

  线程1的两条语句之间没有依赖性,经过指令重排后,有可能inited置为true以后,context还没有初始化。线程2发现inited为true,以为初始化完成,结束循环,用时间还没有初始化的context去执行doSomething()方法。报错。所以我们可以用volatile关键字修饰inited,保证context初始化。

转载于:https://www.cnblogs.com/sunshine-ground-poems/p/10309201.html

你可能感兴趣的文章
数据绑定控件Reperter
查看>>
【codeforces】【比赛题解】#937 CF Round #467 (Div. 2)
查看>>
剑指Offer学习笔记(3)——解决面试题的思路
查看>>
.NET Framework基础知识(二)(转载)
查看>>
Yii DataProvider
查看>>
BestCoder Round #14 B 称号 Harry And Dig Machine 【TSP】
查看>>
hdu 1114 Piggy-Bank
查看>>
maven集成tomcat插件启动报错
查看>>
Boost库编译安装
查看>>
Python matplot画散列图
查看>>
C#/.NET整数的三种强制类型转换(int)、Convert.ToInt32()、int.Parse()的区别
查看>>
算法复习——数位dp(不要62HUD2089)
查看>>
PhpSpreadsheet如何读取excel文件
查看>>
如何选购一款好的人事档案管理系统
查看>>
Spark2.1.0——运行环境准备
查看>>
[转载]C#异步调用四大方法详解
查看>>
在windows下添加php的Imagick扩展
查看>>
python3 爬取百合网的女人们和男人们
查看>>
kubernetes源码阅读笔记——Kubelet(之三)
查看>>
如何利用jQuery post传递含特殊字符的数据
查看>>