为什么我们开发的系统会有并发Bug,并发Bug根源到底是什么?

前言

为什么我们开发的系统会有并发Bug,并发Bug根源到底是什么?

在追问这个问题之前,先说一下一颗剽悍的种子对并发的看法,并发真是一个即熟悉又陌生的课题。熟悉是因为Java是天然支持多线程的,而多线程正是并发的土壤(单线程是不会有并发问题的,JavaScript就是单线程的,你看坐我对面写JavaScript的前端程序员就不会因为并发Bug加班,虽然后端朋友可能不服,但是事实确实如此)。

所以在学习基础时就经过了多线程的洗礼,知道了在多线程下操作没有加锁的集合,数据是多么变化莫测,例如我们在操作Java常用的非线程安全的集合类:HashMap,ArrayList 在多线程下进行put(),add()都会导致不正确的数据结果。

而当脱离了纯粹用模拟多线程示例的学习,到了我们在公司开发的系统真刀真枪发布到线上;所面临的是每一个个的真实用户抵达我们的系统,每个一个用户在计算机中就是一个个的线程。此时我们就得考虑系统的每一个功能在多线程环境下是否是线程安全的。例如我们开发的系统中常遇到有并发Bug场景,例如电商场景下的下单进行购物,出行场景下的火车高铁等抢票等高并发场景。如果不能防范并发问题,当大量用户同时去抢购,库存就面临超卖现象,也就是并发时有Bug。但是造成系统出现并发Bug只不过是结果,我们要探寻的是造成这些并发Bug的原因。

(但这些并发Bug真是我们软件程序员的锅吗?其实并不一定,下面一颗剽悍种子带你找出真正的“锅”)

所以对于这些场景下的多线程不安全问题,我们都有同样的共识,那就是加锁就可以。在单体系统时加本地锁,如常见的:Synchronized,Lock等 ,到了微服务、集群、分布式下的系统时加分布式锁,如:Redis、ZooKeeper。但这并不是让我陌生的地方,真正让我陌生的是为什么要加锁,加锁仅仅是解决问题的手段,而问题的根源是什么?

为什么在多线程下会出现这些问题,为什么我们开发的系统会有并发Bug?

加锁只是答案,为什么加锁才是问题根源!

看过之前一颗剽悍的种子文章的掘友都知道,比起问这个答案是什么,显然我更感兴趣的是这个答案背后是为什么?

那什么是并发,什么又是并行?

在开始前我们得对并发基本概念先有所了解,因为除了并发还有很容易与之混淆的并行。从字面和概念上不好区分之外,并发看上去也好像并行同时进行一样。

先说并发与并行概念,并发其实就是在同一时间点多个线程轮流切换执行。而并行可以同一时间点执行多个线程

(从开发的角度形象的说并发与并行,当我们开发一个系统时,每一个开发系统的职责就好比一个线程,而一个工程师好比一个处理器;并发就像一个全干(全栈)工程师负责完成;是既写前端同时也负责写后端,还要负责搭建服务器等运维工作,在前后端等职责之间来回切换的进行。而并行是多个工程师一起负责完成,可以有前端工程师、后端工程师、数据库工程师、运维工程师等多个工程师同时独立分工的进行)

根源一:上下文切换的原子性问题

我们先来看并发Bug根源一,上下文切换导致的原子性问题,这得从单核CPU时候说起,操作系统和程序就能实现多线程的并发任务。(也就说你既可以在浏览器上的掘金写文章,同时还可以打开音乐听着撩人的DISCO)而看似两个任务同时在运行,其实在计算机底层是CPU给每一个线程分配了执行的时间,也就是时间片(Time Slice),所以线程在执行时是按CPU所分配的时间片内执行任务。

意味着时间片决定了一个线程能占用CPU运行的时长,所以当线程获得的CPU时间片用完,或者被迫暂停运行,就轮到另一个被选中的线程来占用CPU。而一个线程脱离处理器使用权暂停运行就是 “切出”

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

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值