ExecutorCompletionService结果没调用take,poll方法导致的生产事故
事故根本原因-事故代码模拟
public static void test() throws InterruptedException, ExecutionException {
Executor executor = Executors.newFixedThreadPool(3);
CompletionService<String> service = new ExecutorCompletionService<>(executor);
service.submit(new Callable<String>() {
@Override
public String call() throws Exception {
return "HelloWorld--" + Thread.currentThread().getName();
}
});
}
以上代码造成OOM
根源就在于ExecutorCompletionService结果没调用take,poll方法。
正确的写法如下所示:
public static void test() throws InterruptedException, ExecutionException {
Executor executor = Executors.newFixedThreadPool(3);
CompletionService<String> service = new ExecutorCompletionService<>(executor);
service.submit(new Callable<String>() {
@Override
public String call() throws Exception {
return "HelloWorld--" + Thread.currentThread().getName();
}
});
service.take().get();
}
本次事故的核心
当只有调用了ExecutorCompletionService下面的3个方法的任意一个时,阻塞队列中的task执行结果才会从队列中移除掉,释放堆内存,由于该业务不需要使用任务的返回值,则没进行调用take,poll方法。从而导致没有释放堆内存,堆内存会随着调用量的增加一直增长。
所以,业务场景中不需要使用任务返回值的 别没事儿使用CompletionService,假如使用了,记得一定要从阻塞队列中 移除掉task执行结果,避免OOM!