首先咱们在作并发编程的的时候会考虑到原子性丶可见性和有序性,在宏观上会考虑到安全性丶活跃性和性能;git
线程工做内存: 是指 Cpu 的 '寄存器' 和 '高速缓存',线程的 工做内存/本地内存 是指cpu的寄存器和高速缓存的抽象描述,数据读取顺序优先级 是:寄存器->高速缓存->内存github
例如:线程A在主存中年将变量age=0拉去到本身的工做内存中,而后作了age = 5,固然这个操做是在cpu的寄存器中进行的,而后写会高速缓存中,这时线程A的高速缓存还未执行同步主内存的操做,线程B又将age=0从主存拉取到了线程B的工做内存中,致使A线程已经更新可是B线程看不到的可见性问题;编程
例如:当线程A从主内存中将共享变量Count加载到线程A的工做内存后,发生了线程切换,这个时候线程B也将共享变量Count从主内存加载到了线程B的工做内存,这时线程A和B的工做内存中count都是0,线程B执行了Count = Count + 1,而后写回到主内存,这时候线程切换完成,回到了线程A再次执行 Count = Count + 1,再将线程A工做内存计算过的count写回主内存,如今咱们获得的主内存呢中Count值是1而不是2。缓存
在这里讲一个例子,就是获取单例双重检查锁(double-checked locking)判断:安全
/**
* @Auther: lantao
* @Date: 2019-03-28 14:32
* @Company: 随行付支付有限公司
* @maill: lan_tao@suixingpay.com
* @Description: TODO
*/
public class Test1 {
private DoMain doMain;
public DoMain getDoMain(){
if(doMain == null){
synchronized (this.getClass()){
if(doMain == null){
doMain = new DoMain("");
}
return doMain;
}
}else{
return doMain;
}
}
}
复制代码
在上边的代码中在synchronized内和外都有一个if判断,判断doMain是否为null操做,有不少人对synchronized中的if null判断不理解,其实能够这样想,线程A和线程B都执行到了synchronized这里进行竞争锁,结果A获得锁,判断if null,结果还未实例化,继续进行实例化,而后return对象并释放锁,这时线程B获取到了锁进入if null判断,发现doMain已经被线程A实例化过了,直接返回实例便可,第二个if null的做用就在这里;bash
看上去上边的代码是完美的,可是new的操做上咱们理解是:多线程
可是实际上优化后(指令重排)的执行路径多是这样的:并发
博客地址:lantaoblog.site性能