volatile

目录

读volatile修饰的变量     getstatic

写volatile修饰的变量  使用putstatic

volatile是如何保证有序性的:禁止指令重排

指令重排:

屏障:禁止指令重排

happens-before: 

as-if-serial 语义:


cas:乐观锁,假设没有冲突去尝试,直到成功

synchronized :悲观锁,非公平锁(随机唤醒线程,或者唤醒全部),有锁的升级

lock : api层面的锁

 

jvm 内存模型,实际上就是操作系统的一个内存池

读volatile修饰的变量     getstatic

每次读volatile修饰的共享变量都会从主内存中读取,然后再工作内存中生成一个副本,

变量存在一个栈空间中。

 

写volatile修饰的变量  使用putstatic

内存地址中加的锁是 cas 锁,

虚拟机栈中对变量进行修改,然后在主内存地址中对该变量的地址加锁,变成线程独占,

将修改后的值,写入到主内存中,解锁,实现了内存可见性。

内存可见性:内存模型volatile 是基于 Memory Barrier(内存屏障)实现的,jvm 在写入由volatile 修饰的变量后会插进一个Write-Barrier指令,在读这个字段之前插入一个Read-Barrier指令,就可以保证线程a写入变量后,其他线程访问该变量拿到的都是最新值,在写入a 之前的的写操作(前提是a已经写入成功),对其他线程也是可见的。因为 Memory Barrier 会刷出 cache 中所有先前的写入。

jvm 中虚拟机栈:一个线程一个虚拟机栈,随线程的创建而创建,随线程的消失而消失

每个虚拟栈中有多少个栈帧:每调用一次方法就会产生一个栈帧

 

jvm主内存:堆区+方法区

jvm工作内存:虚拟机栈

 

volatile是如何保证有序性的:禁止指令重排

禁止指令重排的过程:

需要使用一个插件才能更加清晰的看到不同,安装 jclasslib 插件,重启idea

使用 -p -v -l 参数,进行反编译,通过-v 参数输出了反编译的附加信息

有 volatile   

没有volatile, 

通过对class 文件进行反编译:生成 上面 Code 代码块的内容

可以看到不管是否是带有 volatile 生成的汇编内容是一样的。

之所以能识别是带有volatile,是由于jvm 会读取 Access flags 的内容

通过 cache->is_volatile() 进行判断是否含有volatile

 

指令重排:

1.编译期指令重排  jvm对代码进行编译优化,会发生指令重排

2.运行期指令重排 (cpu乱序执行带来的):JVM执行的时候,对有依赖性的语句,不会进行重排,对没有依赖性的指令都有可能会发生重排。

 

屏障:禁止指令重排

1.编译期,编译屏障

2.运行期,内存屏障

为什么有内存屏障:

因为CPU写内存机制有两种,
1. write through 异步写 

                    ①CPU将写请求写入 store buffer 中

                    ②CPU空闲的时间将写的数据输入内存(等待空闲的时候出现延迟)

2. write back 同步写

                   ① cpu将写请求写入 store buffer

                   ② 将数据输入内存,直接输入

当有了内存屏障的,在使用异步的方式,写入store buffer中后,将cpu总线上锁,此时CPU 就空闲了,将数据写入内存,这样就达到了同步写的效果。保证了读写的有序性(只有cpu总线解锁了才能进行读操作)。

 

happens-before: 

定义happends-before 规则,就是为了不让jvm对代码进行编译优化,保证并发编程的正确性

规则为:

1.程序的顺序性 ,手动对程序推演的结果一定==编译器最后执行的结果,但是编译器不一定按照推演的顺序编译

2.volatile,对 volatile 变量的写操作 在 读操作之前

3.传递性,a 在b 之前,b在c之前,a一定在c之前

4.锁规则,先解锁,再加锁

5.线程start()规则,线程a 调用线程b,则 b可以看到在调用b之前的操作

6.线程join()规则,线程b 加入到线程 a, 线程b执行完后,线程a 可以看到线程b 的所有操作。

 

as-if-serial 语义:

编译器、runtime和处理器都必须遵守as-if-serial语义,不会对存在数据依赖关系的操作做重排序

 

 

 

评论 1
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值