聊聊并发编程-可见性,原子性和有序性

2 篇文章 0 订阅
1 篇文章 0 订阅

 并发是提升性能的利器,同时也是最容易出bug的。编写正确的并发程序是一件比较困难的事情。并发程序的bug往往会很诡异,同时又难以重现,调试,让人抓狂。但如果我们能理解并发的本质,抽丝剥茧,并能快速,精准的找出产生问题的源头。接下来我们就来分析一下并发问题产生的源头。

        大家都知道CPU,内存,IO设备这三者的速度相差悬殊。我们的程序会有访问内存,IO。根据木桶原理程序的性能取决于最慢者(IO),也就是我们单方面提高CPU性能,内存是无效的。

为了提高CPU的利用率,以及平衡三者的速度差异,操作系统和编译器做了如下措施。

        1、CPU增加了缓存,以平衡CPU和内存的速度差异(将内存数据读入缓存)。

        2、操作系统增加了进程,线程。以分片时间段来使用CPU。

        3、编译器会优化程序的执行顺序(在不影响最终结果前提下)

        以上措施为我们程序带来性能提升,同时许多的程序并发问题也是因此而产生的。

        一、CPU缓存带来并发可见性问题

        一个线程对共享变量的修改,另外一个线程能够看到,我们称为可见性。

        在单核时代,CPU缓存与内存数据一致性是比较容易解决的。所有的线程都是在同一颗CPU运行。一个线程对CPU缓存的变更,另外一个线程是可见的。

 

        但是在多核时代,每颗CPU都有自己的缓存,CPU缓存与内存数据一致性就不是那么容易解决了。当多个线程运行在不同CPU时。假设线程1运行在CPU1上,线程2运行在CPU2上。那么线程1操作的CPU1上的缓存,线程2操作就是CPU2上的缓存。这时候线程1对变量A的操作对于线程2来说就不具备可见性了。这就属于硬件程序给软件程序员挖的坑了。

 

        大家可以尝试用一段代码来验证下多核CPU场景下可见性问题。

        二、线程切换带来并发原子性问题

        我们把一个或者多个操作在CPU执行的过程中不被中断的特性称为原子性。

        由于IO太慢,一个进程在执行IO操作时候可以把自己标记为“休眠状态”并让出CPU使用权。待IO操作执行完成,操作系统会唤醒休眠状态的进程,重新获取CPU使用权。这里进程让出CPU使用权是为了让CPU在这段等待时间段里可以干其他的事情,这样一来CPU的使用率就上来了。这就是任务切换。操作系统做任务切换,可以发生在任何一条CPU指令执行完。是CPU指令,而不是我们的程序的一条语句。我们程序的一条语句可能会对应多条CPU指令。

        例如我们java执行

        count++;

      这条语句对应CPU指令,先从内存读取count变量值,然后将count+1,再将count值刷回内存。如果CPU在执行完从内存获取count变量值为0时候。此时发生任务切换,另外一个线程将count+1并写回内存值为1。然后此线程获取到CPU执行权,将count+1得到的值为1写回内存。此时你会发现对count做了两次+1,最后值却是1。这就是由于任务切换破坏了程序的原子性而产生的问题。

        CPU能保证的是CPU指令原子性操作,而无法保证高级语言操作符的原子性。这需要从高级语言层面来保证高级语言的原子性。

        三、编译器优化带来并发有序性问题

        有序性指的是程序按照代码的先后顺序执行。编译器为了优化性能,有时候会改变程序中的语句的先后顺序。例如程序中

int a=1;

int b=2;

编译器优化后可能变成

int b=2;

int a=1;

        编译器调整了语句的顺序,但是不影响最终结果。不过有时候编译器的优化可能会导致意想不到的bug。

        针对以上问题java是如何解决的呢?

 

个人公众号

欢迎大家关注公众号,一起学习进步

 

 

 

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

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

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

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值