并发编程系列---【数组切割并行查询-解决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.解决方案
-
使用线程安全的集合:
使用Collections.synchronizedList
来包装你的ArrayList
。List<User> resultList = Collections.synchronizedList(new ArrayList<>()); splitList.parallelStream().forEach(sublist -> { List<User> users = userMapper.selectByIds(sublist); resultList.addAll(users); });
-
使用并发集合:
使用CopyOnWriteArrayList
或其他适合的并发集合。List<User> resultList = new CopyOnWriteArrayList<>(); splitList.parallelStream().forEach(sublist -> { List<User> users = userMapper.selectByIds(sublist); resultList.addAll(users); });
-
使用collect操作:
使用流的collect
方法来收集结果,这样可以避免手动处理并发问题。List<User> resultList = splitList.parallelStream() .flatMap(sublist -> userMapper.selectByIds(sublist).stream()) .collect(Collectors.toList());
第三种方法通常是推荐的,因为它更符合流的使用范式,并且处理好了并发问题。
愿你走出半生,归来仍是少年!
【推荐】国内首个AI IDE,深度理解中文开发场景,立即下载体验Trae
【推荐】编程新体验,更懂你的AI,立即体验豆包MarsCode编程助手
【推荐】抖音旗下AI助手豆包,你的智能百科全书,全免费不限次数
【推荐】轻量又高性能的 SSH 工具 IShell:AI 加持,快人一步
· DeepSeek 开源周回顾「GitHub 热点速览」
· 物流快递公司核心技术能力-地址解析分单基础技术分享
· .NET 10首个预览版发布:重大改进与新特性概览!
· AI与.NET技术实操系列(二):开始使用ML.NET
· 单线程的Redis速度为什么快?
2019-12-06 开发中遇到的问题---【feign的多参数问题】