由于不知线程池的bug,某Java程序员叕被祭天
点击上方“JavaEdge”,关注公众号
池化技术常用于缓存创建性能开销较大的对象,即事先创建一些对象成为池中之物,使用时再从池中捞出,用完归还以复用。
手动声明线程池
JDK的Executors
工具类定义了很多便捷的方法可以快速创建线程池。
但是阿里有话说:
他说的弊端案例真的这么严重吗?
newFixedThreadPool 导致 OOM
初始化一个单线程的FixedThreadPool,向线程池提交任务,每个任务都会创建个较大字符串然后休眠
执行程序后不久OOM:
Exception in thread "http-nio-45678-ClientPoller"
java.lang.OutOfMemoryError: GC overhead limit exceeded
newFixedThreadPool
线程池的工作队列直接new个LinkedBlockingQueue
其默认构造器竟然是一个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 cause
java.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
());
参考
《阿里巴巴Java开发手册》
往期推荐
目前交流群已有 800+人,旨在促进技术交流,可关注公众号添加笔者微信邀请进群
喜欢文章,点个“在看、点赞、分享”素质三连支持一下~
评论