言成言成啊 | Kit Chen's Blog

使用sublist遇到的坑

发布于2022-05-14 09:42:04,更新于2022-05-15 20:28:19,标签:java  文章会持续修订,转载请注明来源地址:https://meethigher.top/blog

需求就是因为数据量过大,就实现一个类似于异步分批计算,最后再取回合并的功能。

但是直接使用subList,发现原数组的值被改了,简单的分析了一下代码。

1
2
tempList = list.subList(0, batchNumber);
tempList.clear();

是因为我对截取的List进行了清空处理,导致原List改变了,由此处也可知subList其实是指向了原List截取的部分,如果对他清除了,原List也就会改变了。

发现了这个原因,实现一个分批的功能就简单多了。

分批计算的是项目中的,比较复杂。

我下面以分批保存数据库为例,复现一下这个问题,这是一个完整的例子。

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
/**
* 同步保存
*
* @param list
*/
private void batchSaveSync(List<Student> list) {
int slice = slice(list.size(), batchNumber);
for (int i = 0; i < slice; i++) {
List<Student> tempList;
if (batchNumber > list.size()) {
//前闭后开
tempList = list.subList(0, list.size());
} else {
tempList = list.subList(0, batchNumber);
}
crudRepository.saveAll(tempList);
//因为SubList是指向的地址,如果将该区域清掉,原List也会受到影响,所以就可以继续使用subList从0开始
tempList.clear();
}
}

/**
* 异步通过线程池保存
*
* @param list
*/
private void batchSaveAsync(List<Student> list) {
ExecutorService executorService = new ExecutorConfig().executorService();
int slice = slice(list.size(), batchNumber);
for (int i = 0; i < slice; i++) {
List<Student> tempList;
if (batchNumber > list.size()) {
//前闭后开
tempList = list.subList(0, list.size());
} else {
tempList = list.subList(0, batchNumber);
}
BatchSaveCallable callable = new BatchSaveCallable(tempList);
executorService.submit(callable);
//因为SubList是指向的地址,如果将该区域清掉,原List也会受到影响,所以就可以继续使用subList从0开始
tempList.clear();
}
}


/**
* 分组
* [java分页算法 - SegmentFault 思否](https://segmentfault.com/a/1190000018350964)
*
* @param size
* @param batchNumber
* @return
*/
private Integer slice(int size, int batchNumber) {
return (size - 1) / batchNumber + 1;
}

源码meethigher/batch-save: batch-save

发布:2022-05-14 09:42:04
修改:2022-05-15 20:28:19
链接:https://meethigher.top/blog/2022/sublist/
标签:java 
付款码 打赏 分享
Shift+Ctrl+1 可控制工具栏