1、保持内存可见性
内存可见性:所有线程都能看到共享内存的最新状态。每次读取前必须先从主内存刷新最新的值。每次写入后必须立即同步回主内存当中。
Java通过几种原子操作完成工作内存和主内存的交互:
lock:作用于主内存,把变量标识为线程独占状态。
unlock:作用于主内存,解除独占状态。
read:作用主内存,把一个变量的值从主内存传输到线程的工作内存。
load:作用于工作内存,把read操作传过来的变量值放入工作内存的变量副本中。
use:作用工作内存,把工作内存当中的一个变量值传给执行引擎。
assign:作用工作内存,把一个从执行引擎接收到的值赋值给工作内存的变量。
store:作用于工作内存的变量,把工作内存的一个变量的值传送到主内存中。
write:作用于主内存的变量,把store操作传来的变量的值放入主内存的变量中。
volatile如何保持内存可见性
volatile的特殊规则就是:
read、load、use动作必须连续出现。
assign、store、write动作必须连续出现。
所以,使用volatile变量能够保证:
每次读取前必须先从主内存刷新最新的值。每次写入后必须立即同步回主内存当中。也就是说,volatile关键字修饰的变量看到的随时是自己的最新值。

2、防止指令重排
volatile关键字提供内存屏障的方式来防止指令被重排,编译器在生成字节码文件时,会在指令序列中插入内存屏障来禁止特定类型的处理器重排序。
基于保守策略的JMM内存屏障插入策略:
在每个volatile写操作的前面插入一个StoreStore屏障。
在每个volatile写操作的后面插入一个StoreLoad屏障。
在每个volatile读操作的后面插入一个LoadLoad屏障。
在每个volatile读操作的后面插入一个LoadStore屏障。

对volatile变量的单次读/写操作可以保证原子性的,如long和double类型变量,但是并不能保证i++这种操作的原子性,因为本质上i++是读、写两次操作。

volatile不能完全取代Synchronized的位置,只有在一些特殊的场景下,才能适用volatile。总的来说,必须同时满足下面两个条件才能保证在并发环境的线程安全:
(1)对变量的写操作不依赖于当前值。
(2)该变量没有包含在具有其他变量的不变式中。

最新文章

  1. UML类图关系--继承(泛化)、实现、关联、聚合、组合、依赖
  2. 你的应用是如何被替换的,App劫持病毒剖析
  3. Java线程:线程的交互
  4. [ACM_模拟] ZJUT 1155 爱乐大街的门牌号 (规律 长为n的含k个逆序数的最小字典序)
  5. mongodb driver c#语法
  6. Redis Cluster 3.0搭建与使用
  7. map的相关
  8. 异步编程之Promise(3):拓展进阶
  9. ECshop 二次开发模板教程4
  10. HDU-4678 Mine 博弈SG函数
  11. WPF Customize TabControl
  12. ORA-00031: session marked for kill 标记要终止的会话
  13. 采用objdump调试驱动程序
  14. Android与NativeC传递数据不正确问题
  15. 初学git,初始化库|添加文件ignore|提交方法
  16. Module 的语法
  17. EBS API及接口清单
  18. open-falcon之使用mail-provider发邮件(支持smtp SSL协议)
  19. UOJ268 [清华集训2016] 数据交互 【动态DP】【堆】【树链剖分】【线段树】
  20. 在C#中,如何连接已加密的Sqlite数据库

热门文章

  1. 100725B Banal Tickets
  2. 100741A Queries
  3. 数据结构 station
  4. 属性文件读写测试 PropertiesFileTest
  5. 2018年第九届蓝桥杯国赛总结(JavaB组)
  6. Bugly升级应用集成指南
  7. 无废话MVC入门教程笔记
  8. dubbo事件通知机制 (2)
  9. [Algorithm]线性表
  10. 前端性能优化-gzip