马上注册,结交更多好友,享用更多功能,让你轻松玩转社区。
您需要 登录 才可以下载或查看,没有账号?立即注册
x
标题解决纪录
标题配景:
测试职员反馈某银行体系 “商户费率审核”菜单的“批量审核通过”功能,每次对列表数据批量审核时,总会成功审核一部分,遗留一部分。
标题发现:
经排查,发现以下代码:
- public void function(){
- ...
- List<MerchantRateTmp> list;
- List<String> listM = new ArrayList<>();
- if (rowTotal > 0) {
- list = merchantRateService.getMerchantRateTmpByPage(map);
- list.parallelStream().forEach(v -> {
- listM.add(v.getMchntNo());
- });
- }
- ...
- }
复制代码 对list 列表举行并行流遍历的时间,给一个ArrayList范例的listM列表新增值,再用listM的结果(校验真实性,去重后要审核的商户编号列表)去做审核操纵。但每次对相同的商户费率举行审核,listM的结果都不相同,而且listM列表中会出现许多null 值。
标题剖析:
- parallelStream 是一种并行流,它利用多线程来加速聚集的遍历和操纵。
- ArrayList 是一个非线程安全的聚集类。(HashMap、HashSet同理)
- 当利用 parallelStream 对 ArrayList 举行操纵(添加、删除、修改)时,就会引发线程安全标题。如下:
(1) 数据不一致:多个线程同时修改聚集,可能导致数据丢失或覆盖,丢失表明了为什么listM列表中会出现许多null 值,覆盖表明了为什么会批量审核时没有全部审核。
(2) 并发修改非常:在遍历过程中增删聚集元素,可能会抛出 ConcurrentModificationException。
标题解决
- 将ArrayList 更换为线程安全的聚集类,如 CopyOnWriteArrayList。CopyOnWriteArrayList 通过在写操纵时创建副原来保证线程安全。
- 利用 map、filter 等流操纵天生新的聚集,而不是新建聚集赋值。
- list.stream().map(MerchantRateTmp::getMchntNo).collect(Collectors.toList());
复制代码 - 利用 Collections.synchronizedList将 ArrayList 包装为线程安全的聚集。
- List<String> listM = Collections.synchronizedList(new ArrayList<>());
复制代码 - 数据量少,放弃parallelStream 并行,直接串行。
- list.forEach(v -> listM.add(v.getMchntNo()));
复制代码 - …
标题探索:
举例ArrayList 的 add(E e) 方法:
- /**
- * Appends the specified element to the end of this list.
- * 将指定的元素追加到列表的末尾。
- * add() 方法做了如下操作:
- * 1.检查容量是否足够,如不够将进行扩容,并自增 modCount
- * 2.将指定的元素追加到列表的末尾
- *
- * @param e element to be appended to this list
- * @return <tt>true</tt> (as specified by {@link Collection#add})
- */
- public boolean add(E e) {
- //确保容量足够,如果不够进行扩容
- ensureCapacityInternal(size + 1); // Increments modCount!!
- //将e存在index为size的位置(即最后一位的下一位置),size++
- //我们都知道,++操作不是原子指令,多线程情况下将发生并发问题
- elementData[size++] = e;
- return true;
- }
复制代码 [!TIP]
其中 elementData[size++] = e; 这句代码可以分开为
1.elementData[size] = e;
2.size = size + 1;
当多个线程同时实行以上代码就可能出现:
实行操纵线程一线程二当前步骤结果正确预期往elementData空列表中添加一个值获取size 为0,不用扩容获取size 为0,不用扩容size = 0,
elementData[0]=null,
elementData[1]=nullsize = 0,
elementData[0]=null,
elementData[1]=nullelementData[size] = e;往elementData[0]中添加值Asize = 0,
elementData[0]=A,
elementData[1]=nullsize = 0,
elementData[0]=A,
elementData[1]=null往elementData[0]中添加值Bsize = 0,
elementData[0]=B,
elementData[1]=nullsize = 0,
elementData[0]=A,
elementData[1]=Bsize = size + 1;size+1size = 1,
elementData[0]=B,
elementData[1]=nullsize = 1,
elementData[0]=A,
elementData[1]=Bsize+1size = 2,
elementData[0]=B,
elementData[1]=nullsize = 2,
elementData[0]=A,
elementData[1]=B 具体介绍拜见
1.https://blog.csdn.net/u012859681/article/details/78206494
2.https://blog.csdn.net/weixin_36378917/article/details/81812210
免责声明:如果侵犯了您的权益,请联系站长,我们会及时删除侵权内容,谢谢合作!更多信息从访问主页:qidao123.com:ToB企服之家,中国第一个企服评测及商务社交产业平台。 |