本文从一个小明写的bug 开始,讲bug的发现、排查定位,并由此展开对涉及的算法进行图解分析和源码分析。
事情挺曲折的,因为小明的代码是有单测的,让小明更加笃定自己写的没问题。所以在排查的时候,也经历了前世的500年,去排查排序后的list改动(主要是小明和同事互相怀疑对方的代码,不多说了)。
本文从问题定位之后开始讲:
前言
小明写了一个自定义排序的代码,简化后如下。聪明的你快来帮小明review一下吧。
代码
背景:有一批休息室,status是状态,其中1表示空闲,8表示使用中,2表示在维修。需要按照1空闲<8使用中<2在维修的顺序进行排序。
例如:输入:[1,8, 2, 2, 8, 1, 8],期望输出:[1, 1, 8, 8, 8, 2, 2]。list不为空,数量小于100。
环境:JDK 8
小明的代码如下:
/**
* 排序
*/
private static int compare(Integer status1, Integer status2) {
// 1<8<2 ,按照这样的规则排序
if (status2 != null && status1 != null) {
// 2-维修中, 维修中排到最后面
if (status2.equals(2)) {
return -1;
} else {
// 8-使用中, 排在倒数第二,仅在维修中之前
if (status2.equals(8) && !status1.equals(2)) {
return -1;
}
}
}
return 0;
}
//Test
public static void main(String[] args) {
List<Integer> list = Lists.newArrayList(1, 8, 2, 2, 8, 1, 8);
System.out.println("排序前:"+list);
list.sort(Test::compare);
System.out.println("排序后:"+list);
}
看上面的代码有问题么?别急,咱们先给个入参试一下。
测试
[ 1, 8, 2, 2, 8, 1, 8 ]
public static void main(String[] args) {
List<Integer> list = Lists.newArrayList(1, 8, 2, 2, 8, 1, 8);
System.out.println("排序前:"+list);
list.sort(Test::compare);
System.out.println("排序后:"+list);
}
输出:
排序前:[1, 8, 2, 2, 8, 1, 8]
排序后:[1, 1, 8, 8, 8, 2, 2]
结论:结果是对的,符合预期 。 ( 按照1空闲<8使用中<2维修中的顺序进行排序) 。
嗯,看起来排序是对的。但确实是有问题呢?
(小明OS :哪里有问题?不可能有问题!我本地是好的!)
那我们看看情景复现👉🏻
情景复现
那有什么问题呢?我们再给几个入参试一下 。
case1 : 随机入参
[2, 8, 1, 2, 8, 8, 8, 2, 1]
输出:
排序前:[2, 8, 1, 2, 8, 8, 8, 2, 1]
排序后:[1, 1, 8, 8, 8, 8, 2, 2, 2]
期望是:[1, 1, 8, 8, 8, 8, 2, 2, 2]
结论:结果对,符合预期 ✅。
case2 : 多增加一些数
[1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 2, 2, 2, 2, 2, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 8, 2, 2]
输出:
排序前:[1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 2, 2, 2, 2, 2, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 8, 2, 2]
排序后:[1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 2, 2, 2, 2, 2, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 8, 2, 2]
期望是:[1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 8, 2, 2, 2, 2, 2, 2, 2]
结论:结果不对了,不符合预期 ❌。
case3 : 换几个数
[1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 8, 8, 8, 8, 8, 2, 2, 2, 2, 2, 8, 8, 8, 8, 2, 2]
输出:
排序前:[1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 8, 8, 8, 8, 8, 2, 2, 2, 2, 2, 8, 8, 8, 8, 2, 2]
排序后:[1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 8, 8, 8, 8, 8, 8, 8, 8, 8, 2, 2, 2, 2, 2, 2, 2]
期望是:[1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 8, 8, 8, 8, 8, 8, 8, 8, 8, 2, 2, 2, 2, 2, 2, 2]
结论:结果又对了??
这是什么情况?!
小明有些慌了,越想越觉得奇怪,目前看起来有这样几个看起来些许离谱的结论:
1、可能是和数据量有关系(因为用32位以下的数据,多次Test 也没发现问题),
2、一定和数据数值有关系。(32位以上,有的数据样本没问题,有的有问题)。
3、有问题都在中间部分,而两边是有序的,猜测像排序归并导致的问题。
定位
想查这个问题,小明有三个思路。
一是:代