java 内存可见性
java线程 -> 线程工作内存 -> 主物理内存
线程工作内存的原理是栈内是连续的小空间,寻址速度比堆快得多,将变量拷贝到栈内生成副本再操作
什么是重排序
代码指令可能并不是严格按照代码语句顺序执行的。
大多数现代微处理器都会采用将指令乱序执行的方法,在条件允许的情况,直接运行当前有能力立即执行的后续指令,避免造成等待(CPU的操作速度远快于与物理内存通信的速度),大大提高执行效率。JIT编译器也会做指令重排序操作。
工作内存
每个线程有一个栈,每个栈有一个工作内存,将共享变量读到工作内存后,线程使用的变量值就是自己栈内存中的变量副本了,此时主内存变量发生修改之后,线程工作内存中的值由于已经加载,不会产生对应的变化。
volatile修饰的变量,虚拟机会保证从主内存加载到工作线程的值是最新的。
as if serial
所有的操作都可以为了优化而进行重排序,但是最终的执行结果就像按顺序执行一样,如果有依赖关系,虚拟机会阻止重排序。
异常处理:java异常处理机制也会为重排序做一些特殊处理,也就是插入错误补偿代码,将程序恢复到发生异常时应有的状态。
内存可见性
为了避免处理器访问主内存的时间开销,处理器大多会利用缓存提高性能,因此,处理器上的缓存和主内存的数据并不是实时同步的,各cpu间缓存的数据也不是实时同步的
happens-before
happens-before原则保证了我们的程序执行的可预测性,内存的可见性
- 单线程程序代码次序法则
- 监视器锁法则,对一个监视器锁的解锁 happens-before每一个后续的加锁
- volatile变量法则
- 线程启动法则:thead.start() happens-before 线程里面的动作
- 线程中的动作happen before 线程终结或thread.join
- 传递性原则
内存屏障
内存屏障 Memory Barrier 是一种CPU指令,用于控制特定条件下的重排序和内存可见性
LoadLoad屏障 -> Load1; LoadLoad; Load2 load2及后续读取操作要读取的数据被访问前,load1要读取的数据被读取完毕
StoreStore屏障 Store2及后续写入操作执行前,保证Store1的写入操作对其他处理器可见(刷新到内存)
LoadStore屏障 load1数据装载,之前于Store及后续的存储指令刷新到内存
StoreLoad屏障 保证Store的写入对所有处理器可见先于load操作。该屏障之前的所有内存访问指令(存储和load)完成之后,才执行屏障后的指令它的开销最大,兼具其他3种内存屏障的功能,因此它开销会很昂贵
内存屏障的作用是禁止重排序,虽然表面上是禁用单线程执行的指令重排序,但是间接影响到多线程之前的指令重排序,如保证变量b被操作前,先于b的写操作一定能被其他线程访问到
Thread A:
a=1;
b=true;
Thread B:
if(b){
c = a + 1;
}
volatile
当一个操作是volatile写时,与前面的任何类型的读写都不能重排序,但可以与后面的普通读写重排序
当一个操作是volatile读时,与后面任何类型的操作都不能重排序,与前面的普通读写可以重排序
volatile读与写不能重排序
volatile写使用StoreStore内存屏障,保证前面所有的普通写操作已经对任意处理器可见了,因为StoreStore屏障将保障上面所有的普通写在volatile写之前刷新到主内存
当写入一个volatile变量时,JMM会把该线程对应的本地内存中的共享变量刷新到主内存
当读一个volatile变量时,JMM会把该线程对应的本地内存置为无效,从主内存中读取所有的共享变量。
class VolatileExample {
int a = 0;
volatile boolean flag = false;
public void writer() {
a = 1; //1
//StoreStore,a对flag可见
flag = true; //2
//StoreLoad,flag和a对后续可见
}
public void reader() {
//LoadLoad,flag和a可见
if (flag) { //3
//LoadStore,flag和a可见
int i = a; //4
……
}
}
编译器如果能证明volatile变量只能被单线程访问,那么就可能会把它作为普通变量处理
使用volatile关键字仅能实现对原始变量(如boolen、 short 、int 、long等)操作的原子性
final
对final语义的扩展保证一个对象的构建方法结束前,所有final成员变量都必须完成初始化(的前提是没有this引用溢出)。
CAS在JDK5中被J.U.C包广泛使用,在JDK6中被应用到synchronized的JVM实现中,因此在JDK5中J.U.C的效率是比synchronized高不少的,而到了JDK6,两者效率相差无几,而synchronized使用更简单、更不容易出错,所以它是专家组推荐的首选,除非需要用到J.U.C的特殊功能(如阻塞一段时间后放弃,而不是继续等待)。
参考文章
http://www.cnblogs.com/mengheng/p/3491092.html
https://tech.meituan.com/MySQL_PingCAP_Practice.html
http://www.cnblogs.com/chenyangyao/p/5269622.html
https://blog.csdn.net/u011663071/article/details/78964991
java 内存可见性的更多相关文章
- 一个Java内存可见性问题的分析
如果熟悉Java并发编程的话,应该知道在多线程共享变量的情况下,存在“内存可见性问题”: 在一个线程中对某个变量进行赋值,然后在另外一个线程中读取该变量的值,读取到的可能仍然是以前的值: 这里并非说的 ...
- Java内存可见性
如果一个线程对共享变量的修改,能够被其它线程看到,那么就能说明共享变量在线程之间是可见的.如果一个变量在多个线程的工作内存中都存在副本,那么这个变量就是这几个线程的共享变量.Java内存模型(Java ...
- 从一个小例子引发的Java内存可见性的简单思考和猜想以及DCL单例模式中的volatile的核心作用
环境 OS Win10 CPU 4核8线程 IDE IntelliJ IDEA 2019.3 JDK 1.8 -server模式 场景 最初的代码 一个线程A根据flag的值执行死循环,另一个线程B只 ...
- Java内存可见性volatile
概述 JMM规范指出,每一个线程都有自己的工作内存(working memory),当变量的值发生变化时,先更新自己的工作内存,然后再拷贝到主存(main memory),这样其他线程就能读取到更新后 ...
- 从原子类和Unsafe来理解Java内存模型,AtomicInteger的incrementAndGet方法源码介绍,valueOffset偏移量的理解
众所周知,i++分为三步: 1. 读取i的值 2. 计算i+1 3. 将计算出i+1赋给i 可以使用锁来保持操作的原子性和变量可见性,用volatile保持值的可见性和操作顺序性: 从一个小例子引发的 ...
- 1 Java线程的内存可见性
Java内存的可见性 可见性: 一个线程对共享变量的修改,能够及时被其它线程看到 共享变量: 如果一个变量在多个线程的工作内存中都存在副本,那么这个变量就是这几个线程的共享变量 Java内存模型(JM ...
- 细说Java多线程之内存可见性
编程这些实践的知识技能,每一次学习使用可能都会有新的认识 一.细说Java多线程之内存可见性(数据挣用) 1.共享变量在线程间的可见性 共享变量:如果一个 ...
- Java内存模型——可见性
/** * 可见性问题 * @author Snway * */public class Visibility { private static boolean stop; ...
- Java内存模型JMM与可见性
Java内存模型JMM与可见性 标签(空格分隔): java 1 何为JMM JMM:通俗地讲,就是描述Java中各种变量(线程共享变量)的访问规则,以及在JVM中将变量存储到内存和从内存中读取变量这 ...
随机推荐
- JDK8在windows系统下安装
一.下载 下载地址:https://www.oracle.com/technetwork/java/javase/downloads/index.html#JDK8 目前大部分公司内部使用的还是jdk ...
- 10.扩展:Zero Copy
- jfinal3连接sqlserver2012 使用generator生成model 拉取所有的表
修改MetaBuilder中的getTablesResultSet方法,在schemaPattern的下面一行增加 schemaPattern=dialect instanceof SqlServer ...
- Linux Wait Queue 等待队列
一.引言 linux 内核的等待队列和进程调度息息相关,进程在某些情况下必须等待某些事件的发生,例如:等待一个磁盘操作的终止,等待释放系统资源,或等待指定的时间间隔. 等待队列实现了在事件上的条件等待 ...
- cookie、session和md5加密
cookie Http无状态协议,只能在同一个网站(包括多个页面)下获取,存储在客户端本地的一段信息,帮助我们存储信息获取信息.但是同样有风险:我们自己在浏览器上可以操作或者设置Cookie. con ...
- LinkedList,ArrayList,HashMap,TreeMap
hashMap是无序的,TreeMap是有序的(hashmap是一个链表,而treemap实现了sortedmap()接口所以有序,其实现同时实现比较器) hashSet的底层是根据HashMap来存 ...
- SpringBoot-03-JSR303数据校验和多环境切换
3.3 JSR303数据校验 先看如何使用 Springboot中可以用@Validated来校验数据,如果数据异常则统一抛出异常,方便异常中心统一处理. 这里我们写个注解让name只支持Em ...
- Centos-系统内存信息-free
free 显示系统内存信息,包括物理内存.虚拟内存.共享内存和系统缓存 相关选项 -b 以字节byte为单位显示内存使用情况 -k 以k为单位显示内存使用情况 -m 以MB为单位显示内存使用情况 - ...
- matlab中sum
来源:https://ww2.mathworks.cn/help/matlab/ref/sum.html?searchHighlight=sum&s_tid=doc_srchtitle#btv ...
- P4915 帕秋莉的魔导书(动态开点线段树)
题目背景 帕秋莉有一个巨大的图书馆,里面有数以万计的书,其中大部分为魔导书. 题目描述 魔导书是一种需要钥匙才能看得懂的书,然而只有和书写者同等或更高熟练度的人才能看得见钥匙.因此,每本魔导书都有它自 ...