查看原文
其他

我就辣鸡怎么了?

why技术 why技术 2022-09-10

你好呀,我是why。

是这样的,我周一的时候不是发了《仔细思考之后,发现只需要赔6w》这篇文章吗。

好家伙,我以为这事写个上下集就算是大结局了。

没想到,还需要补一篇来说明一下。

首先,给大家说一声对不起:我错了,行了吧

那篇文章里面有一个基本的论点是错误的,就是这里:

是的,错在了天王老子这一句,脸打的啪啪的,老疼了。

现在,我重新描述一下天王老子这一句:

在 10 个库存,100 个并发的前提下,就算是王母娘娘来了,绝大部分情况下订单数都是 20 个,但绝不可能超过 20 个。

下面我解释一下什么情况下订单数会小于 20 个。

还是拿这个图片来说事:

首先,这个图片我是截取了一部分日志,根据日志画出来的图:

日志里面打印的 Thread-107 的库存是 2,于是我画到图中。

所以我上篇文章里面的推理过程是没有错的,换句话说,那篇文章解释了为什么大多数的情况下订单跑出来都是 20 个,即日志为什么是这样打印的。

虽然我自己跑了不下 100 次,每次都是稳定 20 个。

但是日志一直都这样打,就能推理出订单数一定是 20 个吗?

不能。

是的,不能啊。打完脸之后,我给你分析一下。

问题就出在 Thread-107 查询出库存为 2 这一步,我把情况最简化,重新打上时间标记,基于这个图去说:

首先,T2、T3 时刻一定是晚于 T1 时刻,T2、T3 时刻是推导不出先后关系的,这个不再多说。

那么假设,最开始的情况下库存就是 2 个。

T2 时刻事务还没来得及提交,就执行到 T3 时刻,那么 T3 时刻查询到的库存就为 2。

如果 T2 时刻事务已经提交完成,然后执行到了 T3 时刻,那么 T3 时刻查询到的库存就为 1。

现在,假设 T3 时刻查询到的库存是 1,那么同理,下面的 T4 时刻是不是有可能为 1,也可能为 0:

如果查出来为 0,那么就和前面的文章里面的这个结论冲突:

因为前面文章的这个结论是基于程序的运行日志得出来的。

现在理论有了,那么我怎么模拟一下订单数少于 20 个的情况呢?

想要模拟出这个情况,根据我们前面的分析只需要保证 T3 查询库存的操作晚于 T2 提交事务的操作。

那么自然而然的就想到了在查询库存之前加入睡眠时间:

但是,你会发现这样加,订单每次都是 10 个了呀,这个情况没啥好分析的,就类似于每隔一秒发一个下单请求。锁早就释放了,事务也早就提交了。

所以,我改成了这样:

意思就是如果抢到锁的线程名称包含 1,就休眠一下。

比如模拟程序进入了 GC,发生了 stop the world。

再次执行程序,日志就变成了这样:

可以看到,没有出现连续两个库存为 5,总订单数也变成了 19 个。

验证完成。

甚至,我可以扩大线程名称的命中范围,比如这样,就只有 12 单了:

另外,再提一下另外一个问题。

有的同学用分布式锁去做了验证,发现并没有出现超卖的情况。

可以在释放锁之后加上一个睡眠时间试一试。

这样做的目的是延迟事务提交的时间,以保证下一个抢到锁的线程读到的是未提交之前的库存。

好了,上面说了这么多,就是纠正一下之前文章中说的过于绝对的地方,确实是我写的时候被绕进去了。

我也狡辩一下。

你都不知道,我周末写那篇文章的时候晚上洗澡都在想着去证明一个点:

订单数会不会出现超过 20 的情况?

害,没想到它在 10 到 20 之间埋伏了我一手,防不胜防啊。

我个人是觉得分析小于 20 单的情况比较简单,逻辑也很清楚,还是分析等于 20 单的情况有意思。

最后,给大家分享一下我的这篇文章《当我看技术文章的时候,我在想什么?》

里面表达了我对于看技术博客的态度:

看技术文章的时候多想一步,有时候会有更加深刻的理解。

带着怀疑的眼光去看博客,带着求证的想法去证伪。

多想想 why,总是会有收获的。

另外,写到这里我想起之前知乎看到的一个故事,和大家分享一下。

通过我自己的验证,我跑了上百次的实验,每次都是 20 单。

因为相对于查询语句,事务提交是一个比较重的过程。所以,20 单应该是一个绝大部分同学都会遇到的情况。

但是真的就有一个同学他说他曾经跑出过 19 单的情况,然后他来问我为什么。

原因前面我解释了就不再赘述了。

那假设,如果有人连续 100 次、1000 次甚至上千万次,都跑出了小于 20 的这样的小概率事件。

那么,你的程序的环境的某个环节一定出了大问题。

小概率事件的发生,说明很可能出了大问题。

下面这个知乎回答,分享给你:





推荐👍 :终于结束了!总结一下这次大赛。

推荐👍 :我再说一次:我不是码农,我是工程师!

推荐👍 :提心吊胆!我做支付系统时最害怕的几个问题...

推荐👍 :面试官:给我一个避免消息重复消费的解决方案?

推荐👍 :就这样,我走完了程序员的前五年...

我是 why,你也可以叫我小歪,一个主要写代码,经常写文章,偶尔拍视频的程序猿。

欢迎关注我呀。

您可能也对以下帖子感兴趣

文章有问题?点此查看未经处理的缓存