池化技术罕用于缓存创立性能开销较大的对象,即当时创立一些对象成为池中之物,应用时再从池中捞出,用完偿还以复用。
手动申明线程池
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 开发手册》