可见性、原子性和有序性问题:并发编程Bug的源头

并发编程幕后的故事

随着设备的不断迭代,相应的速度也变得更快。但是在发展的过程中有一个矛盾一直存在,即三者的速度差异。
快慢关系:CPU > 内存 > I/O,程序整体的性能取决于最慢的操作,即读写I/O设备,所以单方面的提升CPU性能是无效的。

为了合理利用CPU的高性能,平衡三者的速度差异,计算机体系结构、操作系统、编译程序做出了贡献,体现为:

  1. CPU增加了缓存,平衡与内存的速度差异
  2. 操作系统增加了进程、线程,以分时复用CPU,进而均衡CPU与I/O设备的速度差异
  3. 编译程序优化指令执行次序,使得缓存能够得到更加合理地利用

现在所有程序都是在享受着这些成果,但是并发程序很多诡异的问题的根源也在这里。

源头一:CPU缓存导致的可见性问题

  • 什么是可见性?
    一个线程对共享变量的修改,另外一个线程能够立刻看到,称之为可见性

单核与内存的关系

所有线程都在一个CPU上执行,CPU缓存与内存的数据一致性容易解决。因为所有的线程操作的是同一个CPU的缓存,一个线程对缓存的写,另一个线程来说一定是可见的。

如下图:线程A和线程B都是操作相同的CPU缓存,所以线程A操作共享变量V的值,线程B访问V的值,一定是V的最新值(线程A写过的值)
单核CPU与内存的关系

多核与内存的关系

多核时代,每个CPU都有自己的缓存,那么保证CPU缓存与内存的数据一致性问题就不怎么容易了,当多个线程在不同的CPU上执行时,这些线程操作的是不同的CPU缓存。

如下图:有两个CPU,对应有两个CPU缓存,线程A和线程B操作在不同的CPU上执行,这时线程A操作的V的值就会对线程B不可见,同理线程B操作的V的值对线程A也不可见。
多核CPU与内存的关系

示例代码:

有一个共享变量count,两个线程t1和t2,线程t1和t2执行方法add10K(),每次add10K会循环10000次count ++操作。


public class Test1 {
   

    private static long count = 0;

    public static void main(String[] args) throws InterruptedException {
   
        final Test1 test1 = 
  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值