场景:
某个定时任务需要多线程执行,执行时间较久且每天只跑一次,想单独拉出一个线程池和其他业务隔离开,交给spring会导致核心线程一直存在 浪费线程资源,因此想单独拉一个池子用完就丢,原本想的是,在execute之后,核心线程会随着线程池对象的回收而回收,后来转念一想,核心线程池怎么回收?写了个main方法试验了一下
public class Test { public static void main(String[] args) { List<Long> memberIds=new ArrayList<>(); for (long i=0;i<3600;i++){ memberIds.add(i); } boolean hasleft=true; int index=0; int pageSize=450; while(hasleft){ int endIndex=Math.min((index+1)*pageSize,memberIds.size()); if (endIndex>=memberIds.size()){ hasleft=false; } List<Long> executeMemberIds=memberIds.subList(index++*pageSize,endIndex); ExecutorService executorService= Executors.newCachedThreadPool(); if (CollectionUtils.isNotEmpty(executeMemberIds)){ executorService.execute(new Runnable() { @Override public void run() { System.out.println(executeMemberIds); } }); } //TODO 很关键 一定要shutdown!否则,不仅核心线程不会回收,业务线程也不会结束,很危险 // executorService.shutdown(); } } }
在没有shutdonwn的时候main方法执行完成后并不会结束线程,自然核心线程也不会被回收,后续了解到核心线程也是可以配置超时时间被回收的,但是一般默认是false,比较好的做法是在把任务交给线程池之后,shutdown()通知线程池,在消费完所有的任务之后回收资源。而shutdownNow()则会终止正在进行的任务进行回收。所以如果没有shutdown,并且不是定时任务的话 这样操作是一个极度极度危险的操作,很快会把线程资源耗尽