volatile是什么

    出去面试的时候,很多面试官都会问你:说说你对volatile的理解。

    下面我将用图的方式告诉大家,volatile是什么?

    

    如上图所示:每个线程都有自己的工作内存,同时还能访问共享内存。

    当两个线程,他们的代码都i需要读取X的值时候, 那么他都会从主内存里加载X变量到自己的工作内存,然后才可以使用X。

    这样,在线程的代码运行过程中,对X的值就可以直接从工作内存中加载了,不需要再从主内存中加载了。

    那么问题来了,为啥每次一定要让线程从工作内存的来读取变量的副本呢,而不是直接去读取共享内存的变量值X不行吗?

      因为线程运行的代码是对应一些指令,是CPU执行的,但是CPu每次执行指令运算,也就是执行我们写的那一大坨代码的时候,是要每次修改这个变量的值的,都是从主内存加载,性能会变差。

      线程内有自己的工作内存的概念,类似于一个本地的缓存,性能会很大提升。

    我们来设想一下,如果线程一,修改了X的值为1,然后将这个修改写入自己的工作内存,那么此时线程1的工作内存值为1.

    而主内存的X还是0,线程2的X还是0,怎么办呢?

    

    如上图所示,线程1和线程2其实都在操作X,但是线程1修改了X,线程2看不到,一直都是看到自己本地工作内存中一个副本的值!

    这就是Java并发编程的可见性问题:

    多个线程并发读写一个共享变量的时候,有可能某个线程修改了变量的值,但是其他线程看不到,也就是对其他线程不可见。

  volatile的作用及背后的原理

    要解决并发编程中的可见性问题,那要怎么办呢,你只要给这个变量定义的加上一个volatile,那么就可以解决了。

    volatile的作用啥是?

      1、一旦X变量定义了volatile来修饰的话,那么线程1,只要修改了X的值,就会在修改完自己工作内存的X变量之后,强制将这个X的值刷新到主内存,必须让主内存的值变成最新的值,整个过程如下图所示:

      2、其二,如果此时有别的线程的工作内存中有这个X变量的本地缓存,也就是一个变量副本的话,那么会让其他线程的工作内存X变量缓存直接失效过期,不允许再次读取和使用,如下图所示:

      3、如果线程2在代码运行中,再次需要读取X变量的值,那么尝试从本地工作内存读取,会发现这个X=0已经过期了。

      也就是必须重新从主内存中加载变量最新的值,那么不就可以读取到X=1的最新的值,整个过程如下图所示:

    对于一个变量加了volatile关键字修饰之后,只要一个线程修改了这个变量的值,立马会强制刷新回主内存,接着强制过期其他线程的工作内存的缓存,最后其他线程读取变量的时候,强制从主内存加载最新的值。

    这样就保证了,任何一个线程修改了变量的值,其他线程立马就可以看见了。

  总结&提醒

    volatile的主要作用还是保证可见性以及有序性。

    有序性涉及到指令重排,内存屏障等概念,但是volatile还是不能保证原子性的。

    也就是说,volatile主要解决一个线程修改了变量的值后,其他线程可以立马读取到最新的值。

    但是如果多个线程同时修改一个变量的值,那还是会可能出现多线程并发安全问题,导致数据修改错乱,也就是说volatile是不负责解决这个问题,也就是不负责解决原子性问题。

    原子性问题主要依靠synchronized,ReentrantLock等加锁机制来解决。

图解volatile的更多相关文章

  1. Java程序员面试必备:Volatile全方位解析

    前言 volatile是Java程序员必备的基础,也是面试官非常喜欢问的一个话题,本文跟大家一起开启vlatile学习之旅,如果有不正确的地方,也麻烦大家指出哈,一起相互学习~ 1.volatile的 ...

  2. [图解Java]读写锁ReentrantReadWriteLock

    图解ReentrantReadWriteLock 如果之前使用过读写锁, 那么可以直接看本篇文章. 如果之前未使用过, 那么请配合我的另一篇文章一起看:[源码分析]读写锁ReentrantReadWr ...

  3. [图解Java]Condition

    图解Condition 0. demo 我先给出一个demo, 这样大家就可以根据我给的这段代码, 边调试边看源码了. 还是那句话: 注意"My" , 我把ReentrantLoc ...

  4. [图解Java]ReentrantLock重入锁

    图解ReentrantLock 0. demo 我先给出一个demo, 这样大家就可以根据我给的这段代码, 边调试边看源码了. 还是那句话: 注意"My" , 我把Reentran ...

  5. Java中this、static关键字的内存图解

    Java中的关键字有很多,abstract  default  goto*  null  switch  boolean  do  if  package  nchronzed  break  dou ...

  6. volatile关键字的详解-并发编程的体现

    xl_echo编辑整理,欢迎转载,转载请声明文章来源.欢迎添加echo微信(微信号:t2421499075)交流学习. 百战不败,依不自称常胜,百败不颓,依能奋力前行.--这才是真正的堪称强大!! 参 ...

  7. 《Java基础知识》Java锁详解(volatile,synchronized等)

    volatile: 让变量每次在使用的时候,都从主存中取. volatile具有synchronized关键字的“可见性”,但是没有synchronized关键字的“并发正确性”,也就是说不保证线程执 ...

  8. 图解Janusgraph系列-分布式id生成策略分析

    JanusGraph - 分布式id的生成策略 大家好,我是洋仔,JanusGraph图解系列文章,实时更新~ 本次更新时间:2020-9-1 文章为作者跟踪源码和查看官方文档整理,如有任何问题,请联 ...

  9. 从JMM透析volatile与synchronized原理,图文并茂

    在面试.并发编程.一些开源框架中总是会遇到 volatile 与 synchronized .synchronized 如何保证并发安全?volatile 语义的内存可见性指的是什么?这其中又跟 JM ...

随机推荐

  1. python3 .format()函数

    Python 3.5.2实验 >>> print('{0},{1}'.format('kzc',18) ) kzc,18 >>> print('{},{}'.for ...

  2. LNMP架构搭建

    目录 一:LNMP架构简介 1.Nginx与uwsgi 二:django框架+python 1.创建用户 2.安装依赖包 3.安装uwsgi和django 4.测试python 5.创建django项 ...

  3. 什么是iptables?

    目录 一:iptables 1.iptables简介 2.什么是防火墙? 3.防火墙种类 二:iptables基本介绍 1.解析内容 三:iptables流程(讲解) 1.流入本机 2.解析(流入本机 ...

  4. linux正则表达式(全面解析)

    目录 一:linux正则表达式介绍 二:普通正则表达式 三:扩展正则 一:linux正则表达式介绍 1.正则表达式的分类(grep) 1.普通正则表达式 2.扩展正则表达式 二:普通正则表达式 ^ : ...

  5. PC端实用正版软件推荐

    首先介绍一下背景,我本人是一个软件工程师,所以对电脑上很多软件使用都有要求,这里将个人觉得好用的一些软件分享给大家: 1. Typora 对于长写本地笔记.网络博客的人,对 MarkDown 格式应该 ...

  6. JVM之栈、堆、方法区(三)

    一.CPU和内存的交互 今天除夕,祝大家新年快乐,其实,我们知道的,我们的CPU跟内存会有非常频繁的交互,因为如果这个频繁的交互是交给我们的磁盘的话,那么随着我们的CPU运转速度越来越快,那么我们的磁 ...

  7. MySQL读写问题(锁)

    一.概述 读-读:并发不存在问题,不需要加锁 写-写:并发存在问题,可能会造成脏写(一个事务没有写完,另一个事务也对相同的数据进行写),但是这种情况,任何一种隔离级别都不允许发生,在隔离级别的时候就解 ...

  8. linux虚拟化

    虚拟化硬件虚拟化:一台物理机虚拟出多台逻辑上的计算机cpu,内存可分配给多个虚拟机 虚拟机中 guestos 的配置有什么用 内存越大越好,CPU也不要太差,如果要用64位虚拟系统或者是Hyper-V ...

  9. ApacheCN 深度学习译文集 20201229 更新

    新增了七个教程: TensorFlow 和 Keras 应用开发入门 零.前言 一.神经网络和深度学习简介 二.模型架构 三.模型评估和优化 四.产品化 TensorFlow 图像深度学习实用指南 零 ...

  10. IDE中集成widfly

    第一步:添加JBOss服务器,Tomcat同理添加 第二步:选择刚刚部署好的服务器 第三步:启动服务: 注意:与Tomcat略有不同的是,启动的根目录可能不相同,导致一直404 查看启动的根目录: 注 ...