最新消息:XAMPP默认安装之后是很不安全的,我们只需要点击左方菜单的 "安全"选项,按照向导操作即可完成安全设置。

这段java代码导致系统雪崩,让我损失了10万季度奖

XAMPP相关 admin 192浏览 0评论

ew0000024

就是下面这段代码,把我给坑惨了:

public static <T> List<T> distinct(List<T> list) {
    if (list == null) {
        return null;
    } else {
        List<T> result = new ArrayList<>();
        for (T item : list) {
            if (!result.contains(item)) {
                result.add(item);
            }
        }
        return result;
    }
}

功能很简单:集合去重,就是这段代码导致系统宕机,服务雪崩,导致扣季度奖没了。

这段代码存在什么问题呢?

可以用下面代码统计一下耗时,count表示集合数据量,可以测试一下count为1万、10万、100万的时候,耗时多少

public static void main(String[] args) {
    //模拟集合数据量
    int count = 10000;
    List<Integer> list = new ArrayList<>();
    for (Integer i = 0; i < count; i++) {
        list.add(i);
    }
    long startime = System.currentTimeMillis();
    List<Integer> distinct = distinct(list);
    System.out.println(count + "数据量,耗时(毫秒):" + (System.currentTimeMillis() - startime));
}

耗时如下

count 耗时
10000 47毫秒
100000 3686毫秒
100万 6分钟

当100万数据的时候,耗时了6分钟,导致处理业务的线程被耗光了,导致大量请求处于等待中,最终导致系统服务雪崩,无法对外提供服务,造成了重大bug。

为什么会出现这样的结果?

我们再回头来看看去重的逻辑:

List<T> result = new ArrayList<>();
for (T item : list) {
    if (!result.contains(item)) {
        result.add(item);
    }
}

这里调用了ArrayList中的contains方法判断result中是否存在item,不存在的时候,将item丢到result集合中,问题就出在了contains这个方法上,ArrayList内部是通过数组来存储数据的,判断原始是否在数组中存在,需要对数组进行遍历,只能按顺序遍历,我们我们看一下遍历的过程中contains内部需要遍历数组多少次

第几次执行result.contains contains时result内部数组元素个数 contains内部需要遍历数组的次数 add后result内部数组元素个数
1 0 0 1
2 1 1 2
3 2 2 3
…. …. ….
n n-1 n-1 n

从上面可以推断出n个数字遍历次数 = n * n / 2,也就是n的平方除以2

n的值 遍历次数
1万 5000万
10万 50亿次
100万 5000亿次

这段代码的根本问题,是没有掌握好ArrayList内部原理,导致了惨重的后果。

下面是优化之后的代码,测试了一下,100万数据,只需要60毫秒,下面这段为什么性能这么高?

public static <T> List<T> distinct(List<T> list) {
    if (list == null) {
        return null;
    } else {
        List<T> result = new ArrayList<>(new HashSet<>(list));
        return result;
    }
}

转载请注明:XAMPP中文组官网 » 这段java代码导致系统雪崩,让我损失了10万季度奖