1.应用场景,今天生产日志监控到一下ArrayList 进行add 异常,具体日志如下:
eptionHandler.handler(178): TXXYBUSSINESS|执行异常
java.util.concurrent.CompletionException: java.lang.ArrayIndexOutOfBoundsException: Index 1 out of bounds for length 0
at java.util.concurrent.CompletableFuture.encodeThrowable(CompletableFuture.java:315) ~[?:?]
at java.util.concurrent.CompletableFuture.completeThrowable(CompletableFuture.java:320) ~[?:?]
at java.util.concurrent.CompletableFuture$AsyncRun.run(CompletableFuture.java:1807) ~[?:?]
at com.txxy.common.support.ThreadContextTaskDecorator.lambda$decorate$0(ThreadContextTaskDecorator.java:20) ~[txxy-common.jar:10.3.10-SNAPSHOT]
at java.util.concurrent.ThreadPoolExecutor.runWorker(ThreadPoolExecutor.java:1136) ~[?:?]
at java.util.concurrent.ThreadPoolExecutor$Worker.run(ThreadPoolExecutor.java:635) ~[?:?]
at java.lang.Thread.run(Thread.java:833) ~[?:?]
Caused by: java.lang.ArrayIndexOutOfBoundsException: Index 1 out of bounds for length 0
at java.util.ArrayList.add(ArrayList.java:455) ~[?:?]
at java.util.ArrayList.add(ArrayList.java:467) ~[?:?]
at com.txxy.api.support.PersonalRiskReportSupport.lambda$riskType4$28(PersonalRiskReportSupport.java:528) ~[classes/:?]
at java.util.concurrent.CompletableFuture$AsyncRun.run(CompletableFuture.java:1804) ~[?:?]
具体代码:
List<DTO> riskSummaryList = new ArrayList<>();
// 10条记录批量查询
Lists.partition(ids, Paging.DEF_PAGE_SIZE).forEach(arrIds -> {
List<CompletableFuture<Void>> list =
arrIds.stream().map(id -> CompletableFuture.runAsync(() -> {
try {
// ....代码省略了
// http请求
if (responseDetail.isSuccess()) {
riskSummaryList.add(new DTO() );
}
} catch (TxxyBusinessException e) {
}
}, apiTaskExecutor)).collect(Collectors.toList());
list.stream().map(CompletableFuture::join).collect(Collectors.toList());
});
result.setRiskSummaryList(riskSummaryList);
上面代码是对ids 分片按照10条记录查询远程接口,并将结果集放到list riskSummaryList 对象中 riskSummaryList.add(new DTO() )最后输出结果.
分析:这种情况是多线程并发情况下添加数据ensureCapacity 这个方法是非线程安全的导致计算值扩容不够抛出的异常。
查看ArrayList源码:
解决方法:
1.使用官网提供的方法Collections.synchronizedList
List list = Collections.synchronizedList(new ArrayList(...));
2.new一个对象CopyOnWriteArrayList方法
new CopyOnWriteArrayList<>()