Java-内存模型 final 和 volatile 的内存语义
前提:内存屏障
内存屏障(Memory Barrier)与内存栅栏(Memory Fence)是同一个概念。
用于阻止指令重排序。保证了特定操作的执行顺序和某些变量的内存可见性。
JMM 内存屏障分为四类:
- Store:将处理器缓存的数据刷新到内存中。
- Load:将内存存储的数据拷贝到处理器的缓存中。
| 屏障类型 | 指令示例 | 说明 |
|---|---|---|
| LoadLoad | Load1;LoadLoad;Load2 | 该屏障确保 Load1 数据的装载先于 Load2 及其后所有装载指令的操作 |
| StoreStore | Store1;StoreStore;Store2 | 该屏障确保 Store1 立刻刷新数据到内存(使其对其他处理器可见)的操作先于 Store2 及其后所有存储指令的操作 |
| LoadStore | Load1;LoadStore;Store2 | 确保 Load1 的数据装载先于 Store2 及其后所有的存储指令刷新数据到内存的操作 |
| StoreLoad | Store1;StoreLoad;Load2 | 该屏障确保 Store1 立刻刷新数据到内存的操作先于 Load2 及其后所有装载装载指令的操作。它会使该屏障之前的所有内存访问指令(存储指令和访问指令)完成之后,才执行该屏障之后的内存访问指令 |
StoreLoad Barriers 同时具备其他三个屏障的效果,是目前大多数 CPU 所支持的。但是相对其他屏障,该屏障的开销相对昂贵。
一、final
https://docs.oracle.com/javase/specs/jls/se8/html/jls-17.html#jls-17.5
声明一个 final 成员时,必须在构造函数退出前设置它的值。
class FinalFieldExample {
final int x;
public FinalFieldExample() {
x = 3;
可见性
final 修饰的变量作为不可变变量,只要对象是正确构造的(没有 this 逃逸发生),不需要任何同步措施就可以保证任何线程都能读到变量在构造函数中被初始化之后的值。
关于this逃逸:
https://www.jianshu.com/p/49068f29a460
https://www.hollischuang.com/archives/2583
有序性
final 写:“构造函数内对一个 final 域的写入”,与, “随后把这个被构造对象的引用赋值给一个引用变量”,这两个操作之间不能重排序。
final 读:“初次读一个包含 final 域的对象的引用” ,与, “随后初次读对象的 final 域”,这两个操作之间不能重排序(先赋值,再调用)。
二、volatile
原子性
32 位的 JDK 中 volatile 修饰后的 long 和 double 也具有原子性。但是 volatile int i = 0;i++; 就不具备原子性,因此可以理解为对单次 volatile 变量的读写操作具有原子性,复合操作(如 i++)不具有原子性。
可见性
编译器会为 volatile 修饰的变量的读写操插入内存屏障,被 volatile 修饰的变量在被修改后可以立即同步到主内存,被其修饰的变量在每次是用之前都从主内存刷新。
有序性
CPU 可能对输入代码进行乱序执行,比如 load->add->save 有可能被优化成 load->save->add。内存屏障同样可以来限制处理器对指令进行重排序。
https://www.hollischuang.com/archives/2673
https://www.jianshu.com/p/aa432a918db9
https://www.jianshu.com/p/157279e6efdb
Java-内存模型 final 和 volatile 的内存语义的更多相关文章
- 全面理解Java内存模型(JMM)及volatile关键字(转载)
关联文章: 深入理解Java类型信息(Class对象)与反射机制 深入理解Java枚举类型(enum) 深入理解Java注解类型(@Annotation) 深入理解Java类加载器(ClassLoad ...
- 全面理解Java内存模型(JMM)及volatile关键字(转)
原文地址:全面理解Java内存模型(JMM)及volatile关键字 关联文章: 深入理解Java类型信息(Class对象)与反射机制 深入理解Java枚举类型(enum) 深入理解Java注解类型( ...
- 深入理解Java内存模型JMM与volatile关键字
深入理解Java内存模型JMM与volatile关键字 多核并发缓存架构 Java内存模型 Java线程内存模型跟CPU缓存模型类似,是基于CPU缓存模型来建立的,Java线程内存模型是标准化的,屏蔽 ...
- Java内存模型之分析volatile
前篇博客[死磕Java并发]—–深入分析volatile的实现原理 中已经阐述了volatile的特性了: volatile可见性:对一个volatile的读,总可以看到对这个变量最终的写: vola ...
- java内存模型-final
与前面介绍的锁和 volatile 相比较,对 final 域的读和写更像是普通的变量访问.对于final 域,编译器和处理器要遵守两个重排序规则: 在构造函数内对一个 final 域的写入,与随后把 ...
- 深入理解java虚拟机(6)---内存模型与线程 & Volatile
其实关于线程的使用,之前已经写过博客讲解过这部分的内容: http://www.cnblogs.com/deman/category/621531.html JVM里面关于多线程的部分,主要是多线程是 ...
- 全面理解Java内存模型(JMM)及volatile关键字
[版权申明]未经博主同意,谢绝转载!(请尊重原创,博主保留追究权) http://blog.csdn.net/javazejian/article/details/72772461 出自[zejian ...
- Java并发编程:JMM (Java内存模型) 以及与volatile关键字详解
目录 计算机系统的一致性 Java内存模型 内存模型的3个重要特征 原子性 可见性 有序性 指令重排序 volatile关键字 保证可见性和防止指令重排 不能保证原子性 计算机系统的一致性 在现代计算 ...
- 简要概述java内存模型,以及volatile关键字
如果我们要想深入了解Java并发编程,就要先理解好Java内存模型.Java内存模型定义了多线程之间共享变量的可见性以及如何在需要的时候对共享变量进行同步.原始的Java内存模型效率并不是很理想,因此 ...
随机推荐
- ubuntu根目录下空间不足,syslog占用很大空间,如何清理?
一激动差点儿删除,以下清理方式是对的 cat /dev/null > /var/log/syslog
- python连接postgres方法
Python使用PyGreSQL操作PostgreSQL: import pg def operate_postgre_tbl_product(): try: #db = pg.connect(dbn ...
- Python中文转为拼音
# -*- coding: utf-8 -*-import sys def openTable(): f = open('gb-pinyin.table', 'r') table = f.read() ...
- spring JdbcTemplate如何返回多个结果集
最近很少发博客,先是去了***公司呆了几年,完全不能上外网,后来又出来了,能上外网了,但项目太忙一直在打码,用的语言也从C#换成了JAVA. 好在两者比较相似,转起来还算方便,近日在操作sqlserv ...
- Diagonal Walking v.2 CodeForces - 1036B (思维,贪心)
Diagonal Walking v.2 CodeForces - 1036B Mikhail walks on a Cartesian plane. He starts at the point ( ...
- zencart新增configuration商店全局变量sql
将下面代码中的 '新增商店变量1', 'ADDS_NAME_1', '新增商店变量1的值', '新增商店变量1描述'换成你需要新增的内容即可. INSERT INTO `configuration` ...
- kotlin面向对象入门
之前在学kotlin基础语法时咱们是采用三方jar包在eclipse工程下进行的,很显然这工具在实际商用中基本上很少用到了,最终是要编写android程序,所以说从这里起得更换一个更加智能更加贴近实际 ...
- 学习使用C语言实现线性表
线性表是最常用且最简单的一种数据结构.一个线性表是n个数据元素的有限序列,序列中的每个数据元素,可以是一个数字,可以是一个字符,也可以是复杂的结 构体或对象.例如:1,2,3,4,5是一个线性表,A, ...
- git生成公钥public key并添加SSH key。git乌龟gerrit下推送git【server sent :publickey】
一.key 码云链接:http://git.mydoc.io/?t=180845#text_180845 博客链接: 方式一:https://blog.csdn.net/xb12369/article ...
- Java笔试题及答案
1.下列不可作为java语言修饰符的是(D) A) a1 B) $1 C) _1 D) 11 答案:java标识符不能以数字开头,包含英文字母,数字,下划线以及$ 2.有一段java 应用程序,它的主 ...