https://www.cnblogs.com/liclBlog/p/9379767.html
补充:
可见性
一个线程修改了变量,其他线程可以立即知道
保证可见性的方法
- volatile
- synchronized (unlock之前,写变量值回主存)
- final(一旦初始化完成,其他线程就可见)
有序性
–在本线程内,操作都是有序的
–在线程外观察,操作都是无序的。(指令重排 或 主内存同步延时)
指令重排
– 线程内串行语义
•写后读 a = 1;b = a; 写一个变量之后,再读这个位置。
•写后写 a = 1;a = 2; 写一个变量之后,再写这个变量。
•读后写 a = b;b = 1; 读一个变量之后,再写这个变量。
•以上语句不可重排
•编译器不考虑多线程间的语义
可重排: a=1;b=2;
指令重排会破坏程序间的有序性
class OrderExample {
int a = 0;
boolean flag = false;
public void writer() {
a = 1;
flag = true;
}
public void reader() {
if (flag) {
int i = a +1;
……
}
}
}
线程A首先执行writer()方法,线程B线程接着执行reader()方法 ,线程B在int i=a+1 是不一定能看到a已经被赋值为1
因为在writer中,两句话顺序可能打乱。
线程A可能是
flag=true
a=1
线程B可能是
flag=true(此时a=0)
防止指令重排的方法是保证线程的安全
指令重排的基本原则
– 程序顺序原则:一个线程内保证语义的串行性
– volatile规则:volatile变量的写,先发生于读
– 锁规则:解锁(unlock)必然发生在随后的加锁(lock)前
– 传递性:A先于B,B先于C 那么A必然先于C
– 线程的start方法先于它的每一个动作
– 线程的所有操作先于线程的终结(Thread.join())
– 线程的中断(interrupt())先于被中断线程的代码
– 对象的构造函数执行结束先于finalize()方法
解释运行
– 解释执行以解释方式运行字节码
– 解释执行的意思是:读一句执行一句
编译运行(JIT)
– 将字节码编译成机器码
– 直接执行机器码
– 运行时编译
编译后的性能有数量级的提升。