在使用CompletableFuture时,发现获取数据时,有时候数据获取不到(值为null)。
代码如下:
package com.example.mavendemo.completablefuture;
import com.google.common.collect.Lists;
import lombok.extern.slf4j.Slf4j;
import java.util.ArrayList;
import java.util.Arrays;
import java.util.Collections;
import java.util.List;
import java.util.concurrent.*;
/**
* @ClassName NullTest.java
* @Description
* @Author chengjiangbo@xinxuan.net
* @DateTime 2024/8/15 11:14
* @Version 1.0
*/
@Slf4j
public class NullTest {
public static void main(String[] args) {
new NullTest().test();
}
public void test() {
//自定义线程池
ThreadPoolExecutor executor = new ThreadPoolExecutor(5, 5, 0, TimeUnit.SECONDS, new LinkedBlockingQueue<>(), new ThreadPoolExecutor.CallerRunsPolicy());
List<Integer> safeList = new ArrayList<>();
List<Integer> numbers = Arrays.asList(0, 10, 20, 30, 40);
List<CompletableFuture> completableFutures = Lists.newArrayList();
for (int i = 0; i < 5; i++) {
int finalI = i;
CompletableFuture completableFuture = CompletableFuture.runAsync(() -> {
try {
Thread.sleep(1000);
} catch (InterruptedException e) {
e.printStackTrace();
}
Integer value = numbers.get(finalI);
safeList.add(value * value);
log.info("异步线程=======>" + Thread.currentThread().getName() + ":" + System.currentTimeMillis());
}, executor);
completableFutures.add(completableFuture);
}
CompletableFuture<Void> allFuture = CompletableFuture.allOf(completableFutures.toArray(new CompletableFuture[completableFutures.size()]));
try{
allFuture.get();
} catch (Exception e){
e.printStackTrace();
}
safeList.stream().forEach(System.out::println);
//关闭线程池
executor.shutdown();
}
}
获取不正常的结果如下:
经过排查发现是居然是List集合的线程安全的问题导致:
// List<Integer> safeList = new ArrayList<>();
//注意,一定要使用线程安全的集合放置值,否组会出现线程安全问题,导致部分数据丢失
CopyOnWriteArrayList<Integer> safeList = new CopyOnWriteArrayList();
再次运行多遍均获得正确结果: