并发编程之内存可见性问题

2022-07-26 17:05:43 浏览数 (1)

内存可见性问题

关于内存可见性问题,简单一点说就是一个线程对内存中的一个共享变量进行修改操作,这个修改操作对其他线程是可见的,说通俗一点, 就是另外一个线程读取这个变量的值是读取修改后的值,也就是最新的值,那么内存不可见显然就是修改操作对其他线程不可见,其他线程 读取到的值可能不是最新的值。

那么引起内存可见性的原因是什么呢?回答是CPU缓存,不过对于单核CPU来说是不存在这个问题的,不过现在都是多核CPU了, 因为CPU中有多个缓存区域,如L1,L2,L3,当线程1从主内存获取共享变量后,对其进行修改后的值可能存在L1,L2,L3中的一个区域,而这对其他线程来说是不可见的,所以就导致 当其他线程对共享变量进行修改以后,此时线程1再去获取变量,因为在缓存中已经命中,获取到的就不是最新的变量,所以这里就出现了数据不一致问题。

单核CPU

对于单核CPU,同一时刻只能有一个线程在执行,所以从主内存中获取到共享变量后,对其进行修改后存放在CPU的缓存中,然后再刷回主内存中, 这整个过程只有一个线程操作,因为为每个线程分配了时间片,所以看起来是多个线程同时执行,但实际上只有一个线程执行,不过在单核CPU上使用多线程其实是完全没必要的, 因为会造成大量的上下文切换。

多核CPU

使用了多核CPU以后,因为每个核都有独立的缓存,所以每个线程操作的缓存可能都不一样,这就造成了共享变量的不可见,因为可能线程1对共享变量就行修改后没来及更新到 主存,而线程2获取到的共享变量是没被线程1修改之前的值,这就造成了数据不一致问题。

Java内存可见性

在Java内存模型中,规定每个线程有一个独立工作区域,叫做工作内存,当一个线程对某个共享变量进行修改操作的时候,先从主存中获取到这个共享变量, 然后保存在自己的工作内存中,对其进行修改后将修改后的值保存在工作内存中,然后更新到主内存中,由于每个线程都有独立的工作内存,所以也是内存不可见的, 现在假如线程1修改了共享变量后,由于内存不可见性,那么其他的线程去主存里面就读取到的就可能是线程1修改之前的变量。

解决内存可见性我们可以通过加锁或者volatile关键字,他们能保证内存的可见性,但是注意,volatile只能保证内存可见性,并不能保证原子性,而加锁可以保证原子性,不过加锁的效率不高,后面我会再接着说锁和volatile。

今天的分享就到这里,我们下期见!

0 人点赞