乐趣区

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

池化技术罕用于缓存创立性能开销较大的对象,即当时创立一些对象成为池中之物,应用时再从池中捞出,用完偿还以复用。

手动申明线程池

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<Runnable>());

参考

  • 《阿里巴巴 Java 开发手册》
退出移动版