Java内存模型如何解决可见性和有序性问题
一. 什么是Java内存模型?
简述:Java的内存模型主要解决多处理器架构下,可见性、有序性的相关问题。
现在我们的计算机处理器架构都是对称多处理器,每个处理器都有自己的寄存器、缓存,多个处理器可以同时执行同一进程下的多个线程,称为处理器的乱序执行。
在Java程序中,不同线程可能访问同一个共享变量,任由处理器或者编译器对这些访问进行优化,会有很多问题出现,因此引入内存模型。
二.三个基本原则
原子性、可见性、有序性
三.Happens-before
Happens-before的理解很抽象,简单说就是‘先于发生‘,单核时代,代码顺序执行,第一行代码先于第二行代码执行,就是第一行 Happens-before 于第二行。
1、程序次序规则
在一个线程中,按照代码顺序(实为控制流顺序,要考虑分支、判断),书写在前面的代码 Happens-before 后面的代码,前面代码产生的变化,对于后面代码可见
2、管程锁
对于同一个锁,上一个锁解锁流程Happens-before下一个锁获取锁资源,上下时间顺序
3、volatile变量
对于一个volatile修饰的共享变量,写操作Happens-before后面的读操作,后为时间顺序
4、线程声明周期
线程的start()方法Happens-before线程内所有内容
线程的内容Happens-before线程终止检测(join()可结束线程,isAlive()检测是否结束并返回)
5、对象终结
一个对象的初始化方法的开始 Happens-before 对象的finalize()方法的开始
6、线程中断
interrupt方法的执行,Happens-before检测线程是否中断的执行
检测线程中断可以使用interrupted()
四.特性:传递性
Class Test{
int x;
volatile boolean f;
void writer(){
x = 42;
f = true;
}
void reader(){
if(f==true){
// 此时x为多少
}
}
}
A执行wirter,B执行reader
- 因为顺序性,执行到ftrue时,x42 先行发生于 f=true,
- 因为volatile修饰f,所以B线程读取f时,A线程写操作先行发生于B线程的读操作
- 如果B线程中已经读到f==true了,从A传递到B,所以x为42
管程的使用
synchronized(this){//自动加锁
//x初始为10,volatile修饰
if(this.x < 12){
x = 12;
}
}// 自动解锁
A、B执行,A先拿到锁资源,那么B看到x=12,因为A的unlock先行发生B的lock
线程的生命周期
Thread A = new Thread(()->
//干点啥都行
)
int x = 100;
A.start();
此处x=100,先行发生于 A.start(),对于干点啥都行,x=100可见
volatile int a;
Thread A = neew Thread(()->
a=100;
)
A.start();
A.join();
// 对于下面的代码a=100可见,join()先行执行于后面代码,