zoukankan      html  css  js  c++  java
  • 一处隐蔽的空指针异常

    记录一个遇到的隐蔽的空指针异常。

    公司里的测试同事之前发现项目里有处偶现的空指针异常。

    大致的代码是这样的:

    private void doWriteTransDetails(List<TransDetailDTO> transDetails) {
      Map<String, List<TransDetailDTO>> transDetailsInvestorMap =
    transDetails.stream().collect(Collectors.groupingBy(item -> item.getInvestor().getName()));

    // 省略
      ......
    }

    对于固定的测试集,多次重跑偶现空指针出现在groupingBy中,乍一看推断是item.getInvestor()为null导致getName()出现空指针。但经过debug查看,实际上是偶现item为null的情况,对于固定的测试集,不应该有这样的偶然因素。

    测试猜测是否是因为多线程环境造成的线程安全问题?但这个list在最上游是在方法中定义的,封闭在栈中,不可能有多个线程操作它。

    经过排查,终于在上游代码中某处发现了元凶。

    public void processTransAppLyList(List<TransDetailDTO> transDetails, List<TransApplyDTO> transApplys) {
      // 省略
      ......
    transApplys.parallelStream().forEach(trans -> {
    TransDetailDTO transDetailDTO = new TransDetailDTO();
    // 省略
         ......
    transDetails.add(transDetailDTO);
    });
      // 下游调用省略
      ......
    }

    源头就是因为此处代码用了并行流,并行流是基于Fork/Join框架实现的。直白点说,这里`transApplys.parallelStream().forEach`是一个多线程的并发环境,对一个`transDetails`进行add操作具有不可预期的结果,可能会数组越界,也可能会元素丢失,也可能会部分index的引用为null。

    由于此处数据量不是太大,且操作复杂度不高,直接把并行流改为普通流即可修复。

    这个比较隐蔽的空指针异常的经验教训是:开发者在考虑用并行流的时候需要再仔细想一下,有必要吗?甚至可以考虑一下有必要用流吗?如果用并行流仍然是需要注意线程安全问题,不要被笼统的`lambda表达式/stream天然是线程安全的`给误导了。





  • 相关阅读:
    knox 编译 源码
    springboot 新建项目
    python 在工程中处理相对路径的思考
    Mac配置虚拟环境Virtualenv,安装Python科学计算包详解
    Python 日志文件处理
    Django与JS交互的示例代码-django js 获取 python 字典-Django 前后台的数据传递
    python for 循环
    Java Script 学习日志 Div
    如何制作windows live writer绿色便携版
    中国大数据企业排行榜V6.0- 5 年后再去看看中几个大数据公司的发展状况
  • 原文地址:https://www.cnblogs.com/micrari/p/6523508.html
Copyright © 2011-2022 走看看