并发编程之可见性、原子性、有序性问题

本文探讨并发编程中的三大问题:可见性、原子性和有序性。CPU缓存导致的可见性问题使得多线程间无法正确同步;线程切换引发的原子性问题可能使操作结果不准确;编译器优化产生的有序性问题可能导致预期之外的执行顺序。文中通过代码示例详细解释了这三个问题,并展示了它们如何影响并发程序的执行效果。
摘要由CSDN通过智能技术生成

并发编程Bug的源头

我们都知道,CPU、内存和I/O设备有着明显的速度差异,而为了合理利用CPU的高性能,平衡这三者之间的速度差异,计算机体系结构、操作系统、编译程序都做出了贡献,主要体现为:

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

这些优化就是并发程序诡异问题的根源所在,总的来说就是缓存导致的可见性问题、线程切换带来的原子性问题、以及编译优化带来的有序性问题。

1. 可见性问题

CPU缓存带来了可见性问题。为什么这么说?我们首先来看下CPU缓存的工作原理:

CPU要读取一个数据时,首先会从缓存中查找,如果找到就立即读取并送给CPU处理;如果没有找到,就用相对慢的速度从内存中读取并送给CPU处理,同时把这个数据所在的数据块调入缓存中,可以使得以后对整块数据的读取都从缓存中进行,不必再调用内存。

在多核时代,每个CPU都有自己的缓存,缓存之间是独立的。多个线程在不同的CPU上执行时,当线程A第一次读取内存中变量V时,就会将V调入缓存中;如果在线程A执行的过程中,线程B修改了V的值;之后A再次读取V,读到的仍是上次调入到缓存中的值,这就产生了可见性问题。

下面我们通过一段代码来分析一下可见性问题。

VisibilityTest.java

public class VisibilityTest {
   
    public static void main(String[] args) throws Exception {
   
        VisibilityThread v = new VisibilityThread();
        v.start();

        Thread.sleep(1000);
        System.out.println("即将置stop值为true");
        v.stopIt();
        Thread.sleep(1000);
        System.out.println("finish main");
        System.out.println("main中通过getStop获取的stop值:" + v.getStop());
    }
}


VisibilityThread.java


public class VisibilityThread extends Thread{
   
    private boolean stop = false;
    @Override
    public void 
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值