Fork me on GitHub

#并发编程的bug源头

cpu 内存 磁盘

核心矛盾就是三者的速度差别 cpu > 内存 > 磁盘

  • 为了解决cpu 增加缓存
  • 操作系统增加进程,线程
  • 编译器优化计算机的指令
    如果有2个线程同时访问cpu中的数据,在单核场景下A线程修改值,B就能发现,这就是可见性。但是要知道一个问题,cpu中是拿到的内存的缓存副本。
    ##线程切换带来的原子性问题

    我们把一个或者多个操作在 CPU 执行的过程中不被中断的特性称为原子性。
    比如一个count +=1 操作就分成三个指令,1 读取到cpu的缓存中,2寄存器执行加操作,3将结果写入内存(缓存机制导致可能写入的是 CPU 缓存而不是内存)

编译器的指令优化带来并发问题

1
2
3
4
5
6
7
8
9
10
11
12
13
    public class Singleton{
static volatile Singleton singleton ; //解决内存可见性问题
private static Singleton getInstance(){
if(singleton==null){
synchronized(Singleton.class){
if(singleton==null){
singleton = new Singlton();
}
}
}
return singleton;
}
}

拿单例来说明编译器,指令重排说明问题,编译器自己会优化命令。

问题就发生在 new Singleton 这里 ,如果发生指令重排线程切换,那么就带来了并发问题。

  1. 分配一块内存 M;
  2. 在内存 M 上初始化 Singleton 对象;
    1. 然后 M 的地址赋值给 instance 变量。
      发生后可能是1,3,2 的顺序

小结 在采用一项技术的同时,一定要清楚它带来的问题是什么,以及 如何规避。

自旋锁 优点不阻塞,但是消耗cpu资源
怎么自己实现自旋锁?
AutoReference 和 compareAndSet (null,Thread)
独占锁/写锁 共享锁/读锁
ReentrantReadWriteLock

##

##

##



本文欢迎转载,但是希望注明出处并给出原文链接。
如果你有任何疑问,欢迎在下方评论区留言,我会尽快答复。
如果你喜欢或者不喜欢这篇文章,欢迎你发邮件到 alonecong@126.com 告诉我你的想法,你的建议对我非常重要。



本文作者: lancecong
联系方式: alonecong@126.com
版权声明: 除特别声明外,所有文章均采用 CC BY-NC-SA 4.0 许可协议。转载请注明出处!

本文欢迎转载,但是希望注明出处并给出原文链接。 如果你有任何疑问,欢迎在下方评论区留言,我会尽快答复。 如果你喜欢或者不喜欢这篇文章,欢迎你发邮件到 alonecong@126.com 告诉我你的想法,你的建议对我非常重要。

------ 本文结束感谢您的阅读! ------
0%