并发的源头:可见性,原子性,有序性

并发的源头

  • 可见性
  • 原子性
  • 有序性
  • 共享数据

可见性

可见性是由于CPU的高速缓存导致的,当线程A操作内存上的变量时,存到CPU缓存中的,当线程B去拿数据时候,不能够读到线程A CPU缓存数据 ,导致结果不一致。该问题为可见性问题

可见性的 解决方案是,在共享变量上加 volatile关键字

原子性

原子性是由于CPU的时间切片导致,当一个共享变量count = 0,执行代码count ++,当A线程拿到执行时间片的时候,把count = 0从内存读取到CPU寄存器中,此时发生时间切片,线程B拿到时间片做了count + 1的操作,并且把count = 1的值写到了内存中,此时CPU再次切换到A线程,A线程寄存器的count还是0,执行count + 1,count值依旧是1,写入内存中。我们原本希望count = 2.但此时count = 1.

原子性的解决方案就是加锁, synchronized或则Lock

有序性
有序性就是按照顺序执行,但是编译器会进行内部优化,可能不会按照我们代码的顺序执行。就会照成有序性问题,看下面的例子

public class Singleton(){
  private Singleton singleton;
  public Singleton getInstance(){
   if(singleton == null){
  	synchronzied(Singleton.class){
  		if(singleton == null){
  			singleton = new Singleton();
}
}
     return singleton;
}
}
  
}

该例子是经典的单例模式,双重检验。看一下 singleton = new Singleton();

我们理解的该行代码的执行顺序应该是

1. 分配一块内存M
2. 在内存M上初始化Singleton对象
3. 然后把M的地址指向singleton变量

实际的执行顺序可能是

1. 分配一块内存M
2. 把M的地址指向singleton变量
3. 在内存M上初始化Singleton对象

当两个线程A, B都调用这块代码的时候,当A线程执行到上图的2.singleton变量不再是null,但是并没有对象初始化,此时时间切片B线程访问就会singleton != null,在使用该变量的时候就会造成NullPointException

  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值