自学内容网 自学内容网

并发编程系列---【数组切割并行查询-解决sql的in超过1000的问题】

1.问题

List<List<Object>> splitList = CollUtil.split(dataList, 800);
List<User> resultList =new ArrayList<>();
// 使用parallelStream输出切割后的结果,每个子列表的大小
splitList.parallelStream().forEach(sublist -> {
   List<User> users = userMapper.selectByIds(sublist);
   resultList.addAll(users);
});

上面这段代码中,resultList是一个ArrayList,而ArrayList是非线程安全的。在并行流的操作中,多个线程可能会同时调用addAll方法,这可能导致竞态条件,可能导致数据丢失或抛出ConcurrentModificationException,解决方案有下面三种,推荐第三种。

2.解决方案

  1. 使用线程安全的集合
    使用Collections.synchronizedList来包装你的ArrayList

    List<User> resultList = Collections.synchronizedList(new ArrayList<>());
    
    splitList.parallelStream().forEach(sublist -> {
        List<User> users = userMapper.selectByIds(sublist);
        resultList.addAll(users);
    });
  2. 使用并发集合
    使用CopyOnWriteArrayList或其他适合的并发集合。

    List<User> resultList = new CopyOnWriteArrayList<>();
    
    splitList.parallelStream().forEach(sublist -> {
        List<User> users = userMapper.selectByIds(sublist);
        resultList.addAll(users);
    });
  3. 使用collect操作
    使用流的collect方法来收集结果,这样可以避免手动处理并发问题。

    List<User> resultList = splitList.parallelStream()
        .flatMap(sublist -> userMapper.selectByIds(sublist).stream())
        .collect(Collectors.toList());

第三种方法通常是推荐的,因为它更符合流的使用范式,并且处理好了并发问题。


原文地址:https://blog.csdn.net/weixin_44988127/article/details/144303833

免责声明:本站文章内容转载自网络资源,如本站内容侵犯了原著者的合法权益,可联系本站删除。更多内容请关注自学内容网(zxcms.com)!