首页 文章详情

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

JavaEdge | 591 2020-12-25 07:09 0 0 0
UniSMS (合一短信)

  点击上方“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 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());

参考

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


往期推荐


大厂如何解决数值精度/舍入/溢出问题

大厂数据库事务实践-事务生效就能保证正确回滚?

线上问题事迹(一)数据库事务居然都没生效?

硬核干货:HTTP超时、重复请求必见坑点及解决方案

给大忙人们看的Java NIO教程之Channel





目前交流群已有 800+人,旨在促进技术交流,可关注公众号添加笔者微信邀请进群


喜欢文章,点个“在看、点赞、分享”素质三连支持一下~

good-icon 0
favorite-icon 0
收藏
回复数量: 0
    暂无评论~~
    Ctrl+Enter