原理上分析下多线程为什么会有可见性问题

先看看4核CPU的结构示意图

在这里插入图片描述

从图中可以看到,CPU一共有3级缓存,分别是L1 cache,L2 cache,L3 cache,经过这3级缓存再加上寄存器,最后才到内存。为什么会有缓存的存在呢,其实这和我们引入Redis的概念是一样的,内存的读写速度比起CPU慢的多,而为了充分的利用CPU的性能,所以在CPU core和内存之间也加入了缓存,数据直接从缓存中读取,就比内存快多了。

那CPU为什么要做多级缓存,一级缓存不就好了?

原因很简单,CPU的内部结构限制了一级缓存的容量大小,所以当一级缓存不够用时,二级缓存顶上,二级缓存不够用时,三级缓存顶上,归根结底,还是为了提高CPU的工作效率。

使用了多级缓存之后,引发的问题

直接用一个读取和修改的流程来阐述这个问题。假设要读取变量a,core1会先从内存读取,然后途径L3 cache,
L2 cache,寄存器,L1 cache,然后core1修改了变量a的值,刚写到L1 cache,准备慢慢的走过L3 cache,
L2 cache,寄存器,最后写回到内存中时,core4也要读取了变量a,它也是从内存开始读,这时候,由于core1还没把被修改的变量a的值同步回内存,所以core4拿到的就是旧的变量a的值,就引发了多线程可见性的问题了。

那JMM(Java内存结构)又是怎么样的呢?

JMM没有搞得那么复杂,它把以上的复杂结构抽象成了主内存和工作内存,示意图如下:

在这里插入图片描述

从图中可以发现,每个线程都有自己的工作内存,工作内存中存的是主内存共享变量的副本。线程如果想要得到共享变量的值,只能先把相应的主内存变量读到自己的工作内存中,然后再从工作内存中读取,修改之后写回工作内存,最后再同步回主内存。而各个线程间的工作内存是不共享的,所以如果线程一修改了某个变量的值,线程二想要看到,就得等线程一把变量同步回主内存中,才能看到这次变化,读取到最新的值,否则读取的话很可能就是过期的变量值,也就引发了多线程的可见性问题。

总结

通过上述的分析,对多线程为什么有可见性问题,也会有更深的理解。

原创文章 358 获赞 387 访问量 7万+

猜你喜欢

转载自blog.csdn.net/weixin_38106322/article/details/105745555
今日推荐