Volatile内部原理

前言:多线程内存的划分分为:java线程、工作内存、save和load操作、主内存

volatile内部原理

volatile变量赋值后,汇编代码会多一个lock操作,相当于内存屏障,作用是使本CPU的缓存写入内存(相当于store和write操作),该写入动作会使其他cpu的缓存无效,所以valatile变量的修改对其它cpu立即可见。

 

volatile的变量新增的内存语义

1、工作内存中,每次使用使用对象前必须先从主内存刷新最新的值。(其它cpu能看到变量最新的值)

2、工作内存中,每次修改变量后必须立刻同步会主内存中。(其它线程可以看到本线程对变量的修改)

3、volatile修饰的变量不会被指令从排序优化。(a肯定在b之前执行)

volatile boolean a;

int i=3;

int j=5;

volatile boolean b;

 

volatile作用

1、只能保证变量对所有线程的可见性,不能保证原子性和有序性。

2、每次使用前,都要先刷新,执行引擎看不到不一致的情况,因此可以认为不存在一致性的问题。

3、使用Volatile变量会禁止指令重排序优化,其实就是内存屏障的作用,(volatile前的代码不会在volatile变量之后执行,volatile变量之后的代码也不会在volatile变量之前执行),保证代码的执行顺序与程序的顺序相同。

4、每次使用变量前必须从主内存刷新最新的值,每次修改变量后必须立刻同步回主内存中。

5、目前商用虚拟机几乎都把64位的数据读写操作作为原子操作来对待。

 

JMM有8种原子的内存语义操作

1、lock(锁定):作用于主内存的变量,它把一个变量标识为一条线程独占的状态。

2、unlock(解锁):作用于主内存的变量,它吧一个处于锁定状态的变量释放出来,释放后的变量才能被其它线程锁定。

3、read(读取):作用于主内存的变量,它把一个变量的值从主内存传输到线程的工作内存中,以便随后的load作用。

4、load(载入):作用于工作内存的变量,它把read操作从主内存中得到的变量值放入到工作内存的变量副本中。

5、assign(赋值):作用于工作内存的变量,它把一个从执行引擎接收到的值赋给工作内存的变量。

6、store(存储):作用于工作内存的变量,把工作内存的变量传到主内存中,以便随后write操作。

7、write(写入):作用于主内存的变量,把store操作从工作内存中的变量放到主内存中。

 

JMM的8中基本操作必须满足的规则

1、不允许read和load、store和write操作之一单独出现

2、发生过assign操作,必须把变量在工作内存改变后必须同步会主内存(同步的时间点不一定)

3、没有发生过assign操作,不允许把数据从工作内存同步回主内存

4、新变量只能从主内存诞生

5、一个变量同一时刻只允许一个线程对其进行lock操作,但可被同一线程多次lock,lock几次就要unlock几次(synchronized同步代码块原理实现方式)

6、一个变量执行lock操作会清空工作内存中该变量的值

7、变量没有执行lock操作则不能执行unlock操作

8、对变量执行unlock前,必须把此变量同步回主内存(synchronized同步块可见性实现原理)

 

原子性

1、基本数据类型的访问读写是具备原子性的

2、lock和unlock操作没有开放个用户直接使用,但是提供了更高级别的字节码指令monitorenter和monitorexit,也就是java中的synchronized快

可见性

1、synchronized和final关键字也具有可见性

2、synchronized可见性是因为,对一个变量执行unlock前,必须先把变量同步回主内存中(执行store和write操作)这条获得的。

3、final可见性,被final修饰的字段在构造器中一旦初始化完成,其它线程就能看见该字段的值。

有序性

1、synchronized的有序性是通过 一个变量在同一时刻只允许一个线程对其进行lock操作 获得的。

 

先行先发原则的作用

判断数据是否存在竞争,线程是否安全的依据。

JMM中的顺序性不能仅仅依靠volatile和synchronized.

先行发生原则和时间的先后顺序没什么关系

什么是先行先发原则

A操作先行发生于B操作,那A操作的影响能被B操作观察到。(影响包括内存共享变量值的改变、发送消息、调用方法等)

1、程序次序:一个线程内,按照程序代码的顺序,写在前面的操作先行发生于后面的操作。

2、synchronized相关:unlock先于后面的lock

一个unlock操作先行发生于后面对同一个锁的lock操作。(后面只时间的先后)

3、volatile相关:写先于读

对volatile的写操作先行发生于后面对这个变量的读操作。(后面只时间的先后)

线程相关

4、start():Thread的start()方法先行发生于此线程的每一个动作。(start()先于所有动作)

5、join()或isAlive():线程中的所有操作先行发生于对此线程的终止检验(所有动作先于Thread.join方法结束、Thread.isAlive等)

6、interrupt():线程中断先行发生于对中断检验代码(interrupt()先于Thread.interrupted())

7、finalize():初始化方法的完成先于finalize()的开始

8、传递性:A操作先于B操作,B操作先于C操作,那A操作先于C操作。

 

 

 

發表評論
所有評論
還沒有人評論,想成為第一個評論的人麼? 請在上方評論欄輸入並且點擊發布.
相關文章