写点什么

由于不知线程池的 bug, 某 Java 程序员叕被祭天

发布于: 2020 年 12 月 22 日

池化技术常用于缓存创建性能开销较大的对象,即事先创建一些对象成为池中之物,使用时再从池中捞出,用完归还以复用。


手动声明线程池


JDK 的Executors



但是阿里有话说:



他说的弊端案例真的这么严重吗?


newFixedThreadPool 导致 OOM


初始化一个单线程的 FixedThreadPool,向线程池提交任务,每个任务都会创建个较大字符串然后休眠



执行程序后不久 OOM:



Exception in thread "http-nio-45678-ClientPoller"   java.lang.OutOfMemoryError: GC overhead limit exceeded
复制代码



newFixedThreadPool


其默认构造器竟然是一个Integer.MAX_VALUE


虽然使用newFixedThreadPool可以固定工作线程数量,但任务队列几乎无界。如果任务较多且执行较慢,队列就会快速积压,内存不够就很容易导致 OOM。


newCachedThreadPool 导致 OOM


[11:30:30.487] [http-nio-45678-exec-1] [ERROR] [.a.c.c.C.[.[.[/].[dispatcherServlet]:175 ] - Servlet.service() for servlet [dispatcherServlet] in context with path [] threw exception [Handler dispatch failed; nested exception is java.lang.OutOfMemoryError: unable to create new native thread] with root causejava.lang.OutOfMemoryError: unable to create new native thread
复制代码

OOM 是因为无法创建线程,newCachedThreadPool 这种线程池的最大线程数是 Integer.MAX_VALUE,基本无上限,而其工作队列 SynchronousQueue 是一个没有存储空间的阻塞队列。所以只要有请求到来,就必须找到一条工作线程处理,若当前无空闲线程就再创建一个新的。


由于我们的任务需 1 小时才能执行完成,大量任务进来后会创建大量的线程。我们知道线程是需要分配一定的内存空间作为线程栈的,比如 1MB,因此无限创建线程必然会导致 OOM:


public static ExecutorService newCachedThreadPool() {    return new ThreadPoolExecutor(0, Integer.MAX_VALUE,                                  60L, TimeUnit.SECONDS,                                  new SynchronousQueue<Runnable>());
复制代码


参考


  • 《阿里巴巴 Java 开发手册》


用户头像

还未添加个人签名 2020.09.07 加入

还未添加个人简介

评论

发布
暂无评论
由于不知线程池的bug,某Java程序员叕被祭天