还记得之前面某大公司回答volatile当时说的多么的垃圾,幸好当时离秋招还早。。。所以种一棵树最好的时机是十年前,其次是现在 ♡♡♡
volatile:是java虚拟机提供的轻量级的同步机制
三大特性:
1:保证可见性【某一个线程修改数据并写回主物理线程,另外的线程要立刻知道(机制)称为它的可见性】
2:不保证原子性【number++在多线程下是非安全的】
3:禁止指令重排
如何解决原子性?
1:加synchronized
2:使用JUC下AtomicInteger
JMM:java内存模型【java Memory Model】并不真实存在
四大特性:
1:可见性
2:原子性
3:有序性
【VolatileDemo代码演示可见性+原子性代码】
class MyData{
volatile int number =0;
// int number=0;
public void addTo() {
this.number=60;
}
}
public class VolatileDemo{
public static void main(String[] args) {
MyData myData = new MyData();
new Thread(()->{
System.out.println(Thread.currentThread().getName()+"\t come in");
try {
TimeUnit.SECONDS.sleep(3);
} catch (Exception e) {
e.printStackTrace();
}
myData.addTo();
System.out.println(Thread.currentThread().getName()+"\t updated number value"+myData.number);
},"AAA").start();
//如果number没有变则进入死循环
while (myData.number==0) {
}
System.out.println(Thread.currentThread().getName()+"\t mission is over "+myData.number);
}
}
指令重排:
源代码-->编译器优化的重排-->指令并行的重排-->内存系统的重排-->最终执行的指令
多线程环境中线程交替执行,由于编译器优化重排的存在,两个线程中使用的变量能否保证一致性是无法确定的,结果无法预测
volatile实现了禁止指令重排优化,从而避免多线程环境下出现乱序执行的现象
内存屏障【Memory Barrier】又称内存栅栏,是一个CPU指令,它的作用有两个:
1:保证特定操作的执行顺序
2:保证某些变量的内存可见性【利用该特性实现volatile的内存可见性】
由于编译器和处理器都能执行指令重排优化,如果在指令插入一条Memory Barrier则会告诉编译器和CPU,不管什么指令都不能和这条Memory Barrier指令重排序,也就是说通过插入内存屏障禁止在内存屏障前后的的指令执行重排序优化。内存屏障另外一个作用是强制刷出各种CPU的缓存数据,因此任何CPU上的线程都能读取到这些数据的最新版本