java:volatile关键字原理
volatile说明
在变量中声明后,能够在所有线程中共享改变量。并且volatile关键字能防止指令重排,即程序读取到volatile时,则不会将程序执行顺序修改。
先了解下内存模型
cpu内存模型

多核cpu在处理数据时,会通过系统总线把主内存中的数据读取副本到高速缓存中的缓存行,当其中一个cpu修改了当前缓存行的数据,会有两种方式保证数据的一致性
1、总线锁:因为高速缓存交互主存是需要通过系统总线的,所以修改后会将总线锁定,阻塞其它CPU访问主存,等当前CPU缓存写入到主存后释放锁。其它CPU才能从主存中读取数据。这种方式效率极低,影响其它CPU访问内存。
2、缓存一致性(MESI):当前CPU缓存行数据修改,通过总线将修改状态广播给其它CPU,让各个CPU根据状态判断本地情况进行响应,是失效还是重新读

java内存模型
JVM内存结构,把内存分为 堆、栈、方法区、本地方法栈和程序计数器。其中堆和方法区被所有线程共享,在内存模型中被成为主内存,而栈、程序计数器属于线程私有,在内存模型中被成为工作内存。
Java内存模型规定所有的变量都是存在主存当中(类似于前面说的物理内存),每个线程都有自己的工作内存(类似于前面的高速缓存)。线程对变量的所有操作都必须在工作内存中进行,而不能直接对主存进行操作。并且每个线程不能访问其他线程的工作内存。
volatile作用
java中内存模型没有像CPU一样的总线来保证线程数据共享。这时候就需要volatile,volatile会强制将每个线程工作内存的变量修改主动的保存主存中。要读取时再从主存中读取

使用volatile达到的线程间变量共享的问题。但是无法保证数据原子性
因为多个线程同时执行,读取赋值写入,那么volatile修饰的变量则会已程序执行时的最后一个线程修改的参数为准。
保障volatile原子性
保障原子性的方式有三种synchronized、lock、atomic
两者是锁住当前变量的操作线程。
atomic是java提供的CAS来实现原子性操作
应用场景
需要通过某个状态控制调用volatile变量的线程(只有一个线程写,其它线程读)
与static区别
相同点:
1、都是为了保证线程共享
2、非原子性(操作变量)
不同点:
volatile唯一的好处就是多线程可以及时获取到最新的主存数据,这点跟static有点区别。static在多线程状态下可能获取不到最新数据。
JVM规范定义了线程对内存间交互操作:
Lock(锁定):作用于主内存中的变量,把一个变量标识为一条线程独占的状态。
Read(读取):作用于主内存中的变量,把一个变量的值从主内存传输到线程的工作内存中。
Load(加载):作用于工作内存中的变量,把read操作从主内存中得到的变量的值放入工作内存的变量副本中。
Use(使用):作用于工作内存中的变量,把工作内存中一个变量的值传递给执行引擎。
Assign(赋值):作用于工作内存中的变量,把一个从执行引擎接收到的值赋值给工作内存中的变量。
Store(存储):作用于工作内存中的变量,把工作内存中的一个变量的值传送到主内存中。
Write(写入):作用于主内存中的变量,把store操作从工作内存中得到的变量的值放入主内存的变量中。
Unlock(解锁):作用于主内存中的变量,把一个处于锁定状态的变量释放出来,之后可被其它线程锁定。
上面一段,只要知道,工作内存中保留了一份主存中的变量副本,因此写操作未必能马上更新到主存,读操作也未必能马上读取到主存中更新后的值,这与cpu时间片有关,能不能读取最新的值看缘分。
参考:
static和volatile的原理及区别:https://blog.csdn.net/x18094/article/details/108429511
Java并发编程:volatile关键字解析:https://www.cnblogs.com/dolphin0520/p/3920373.html
存储器 - 缓存一致性 MESI 协议:如何让多核CPU的高速缓存保持一致:https://www.cnblogs.com/binarylei/p/12590759.html
java:volatile关键字原理的更多相关文章
- Java volatile 关键字底层实现原理解析
本文转载自Java volatile 关键字底层实现原理解析 导语 在Java多线程并发编程中,volatile关键词扮演着重要角色,它是轻量级的synchronized,在多处理器开发中保证了共享变 ...
- [Java并发编程(三)] Java volatile 关键字介绍
[Java并发编程(三)] Java volatile 关键字介绍 摘要 Java volatile 关键字是用来标记 Java 变量,并表示变量 "存储于主内存中" .更准确的说 ...
- 13、Java并发性和多线程-Java Volatile关键字
以下内容转自http://tutorials.jenkov.com/java-concurrency/volatile.html(使用谷歌翻译): Java volatile关键字用于将Java变量标 ...
- Java Volatile关键字(转)
出处: Java Volatile关键字 Java的volatile关键字用于标记一个变量“应当存储在主存”.更确切地说,每次读取volatile变量,都应该从主存读取,而不是从CPU缓存读取.每次 ...
- Java volatile关键字详解
Java volatile关键字详解 volatile是java中的一个关键字,用于修饰变量.被此关键修饰的变量可以禁止对此变量操作的指令进行重排,还有保持内存的可见性. 简言之它的作用就是: 禁止指 ...
- Java volatile关键字实现原理
场景引入 可见性问题 先来看一张图: 上面的图,是简化版的Java内存模型,一个线程有自己的工作内存,同时还有一个共享的主内存. 线程1和线程2读取数据data时,先从主内存里加载data变量的值到工 ...
- 从根源上解析 Java volatile 关键字的实现
1.解析概览 内存模型的相关概念 并发编程中的三个概念 Java内存模型 深入剖析Volatile关键字 使用volatile关键字的场景 2.内存模型的相关概念 缓存一致性问题.通常称这种被多个线程 ...
- java volatile 关键字(转)
volatile这个关键字可能很多朋友都听说过,或许也都用过.在Java 5之前,它是一个备受争议的关键字,因为在程序中使用它往往会导致出人意料的结果.在Java 5之后,volatile关键字才得以 ...
- Java Volatile关键字
在当前的Java内存模型下,线程可以把变量保存在本地内存(比如机器的寄存器)中,而不是直接在主存中进行读写. 这就可能造成一个线程在主存中修改了一个变量的值,而另外一个线程还继续使用它在寄存器中的变量 ...
随机推荐
- Electron 开发音视频
废话不多说,咱直接进入正题! 创建 Electron 项目 前提条件 在使用Electron进行开发之前,需要安装 Node.js. 要检查 Node.js 是否正确安装,请在您的终端输入以下命令: ...
- SpringBoot 默认json解析器详解和字段序列化自定义
前言 在我们开发项目API接口的时候,一些没有数据的字段会默认返回NULL,数字类型也会是NULL,这个时候前端希望字符串能够统一返回空字符,数字默认返回0,那我们就需要自定义json序列化处理 Sp ...
- 移植TensorFlow到Windows平台
2015年11月,Google宣布开源旗下机器学习工具TensorFlow,引发业界热潮.TensorFlow原生支持*unix系和安卓平台,但并不提供对Windows平台的支持.如果想在Window ...
- HttpRunner3源码阅读:7.响应后处理 response.py
response 上一篇说的client.py来发送请求,这里就来看另一个response.py,该文件主要是完成测试断言方法 可用资料 jmespath[json数据取值处理]: https://g ...
- ElasticSearch入门检索
前面简介说到 elsatic是通过RestFul API接口操作数据的,可以通过postman模拟接口请求测试一下 一._cat 1.GET /_cat/nodes:查看所有节点 2.GET /_ca ...
- C语言复习(六)----typedef 的作用
typedef的作用 重命名变量:typedef unsigned int Uint;//可以使用Uint代替unsigned int 定义新的数据类型 typedef struct Books{ c ...
- 2021字节跳动校招秋招算法面试真题解题报告--leetcode19 删除链表的倒数第 n 个结点,内含7种语言答案
2021字节跳动校招秋招算法面试真题解题报告--leetcode19 删除链表的倒数第 n 个结点,内含7种语言答案 1.题目描述 给你一个链表,删除链表的倒数第 n 个结点,并且返回链表的头结点. ...
- spring cloud alibaba版本选择
https://github.com/alibaba/spring-cloud-alibaba/wiki/版本说明 Spring Cloud Version Spring Cloud Version ...
- mysqldump备份总结
常用的备份参数 -A 备份全库 -B 备某一个数据库下的所有表 -R, --routines 备份存储过程和函数数据 --triggers 备份触发器数据 --master-data={1|2} 告诉 ...
- java线程池 面试题(精简)
什么是线程池? 线程池是一种多线程处理形式,处理过程中将任务提交到线程池,任务的执行交由线程池来管理. 如果每个请求都创建一个线程去处理,那么服务器的资源很快就会被耗尽,使用线程池可以减少创建和销毁线 ...