线程池的不正确使用引发的问题
public static void main(String[] args) throws InterruptedException {
Cache<Long> cache = new Cache<Long>(() -> {
TimeUnit.SECONDS.sleep(2);
return 0l;
}, 3, ChronoUnit.SECONDS);
ThreadPoolExecutor executor = new ThreadPoolExecutor(2, 5, 30, TimeUnit.SECONDS, new ArrayBlockingQueue<>(10));
for (int i = 0; i < 20; i++) {
System.out.println("提交"+i);
executor.submit(() -> {
System.out.println(Thread.currentThread().getName() + ">>>>" + cache.get());
});
}
System.out.println("提交完成");
executor.shutdown();
while (!executor.isTerminated()) {
}
System.out.println("over");
}
描述:
使用线程池来执行任务,配置如下:
ThreadPoolExecutor executor = new ThreadPoolExecutor(2, 5, 30, TimeUnit.SECONDS, new ArrayBlockingQueue<>(10));
执行了20个任务,始终没有看到<<提交完成>>,而且程序一直没有退出。
分析:
核心线程数是2,所以一开始会创建2个线程,使用ArrayBlockingQueue,边界为10,后来又创建了3个线程,这个时候如果在提交新的任务,就会执行拒绝策略,而默认的RejectHandler是AbortPolicy,是直接抛出异常,此时主线程已经中止了,无法执行shutdown操作。主线程中止了,但是为什么进程没有退出?是因为此时线程池里面的线程还没有回收,在存在非守护线程的情况下,jvm进程没法退出。过了半个小时,进程仍然没有退出,是因为core的值是2,也就是线程池会从5个线程回收到2个,但是会仍然存在两个线程的,所以一直无法退出。
修正:
- 更换拒绝策略,保证程序会执行到shutdown
- 修改核心线程数为0,保证抛出异常后,线程池会把所有执行完的线程回收,jvm进程自动退出