并发理论知识-并发源头

74 阅读1分钟

并发源头

一、cpu缓存导致的可见性问题

image.png -+96

多核 CPU 的缓存与内存关系图

Java解决方案

通过内存模型的 Happens-Before 规则解决,即volatile关键字、sychronized锁等

二、线程切换带来的原子性问题

程序的一个操作语句在我们看来是一个不可分割的整体,但却可以拆分成多条cpu指令。
我们把一个或者多个操作在 CPU 执行的过程中不被中断的特性称为原子性

Java解决方案

原子性问题是因为有线程切换,通过互斥锁来保证同一时刻只有一个线程执行

三、编译优化带来的有序性问题

经典案例:利用双重检查创建单例对象

public class Singleton{
    private Singleton instance;
    
    public Singleton getSingleton(){
        if(sinstance == null) {
            synchorized(instance){
                if(instance == null){
                    instance = new Singleton();
                }
            }
        }
        return instance;
    }
}

创建对象:优化前

  1. 申请一块内存M
  2. 在M上初始化Singleton对象
  3. 然后将M的地址赋值给Singleton

创建对象:优化后

  1. 申请一块内存M
  2. 将M的地址赋值给Singleton
  3. 在M上初始化Singleton对象

所以在第一个if判断时,可能导致不通过,而返回一个未初始化的对象,导致空指针异常。

Java解决方案

通过内存模型的 Happens-Before 规则限制优化