大家好,我是哪吒。
在程序开发中,高并发场景越来越多,线程池首当其冲。
简单回顾一下:
《阿里巴巴 Java 开发手册》强制禁止,线程池不允许使用Executors创建,而是通过ThreadPoolExecutor的方式创建,这样的处理方式能让编写代码的工程师更加明确线程池的运行规则,避免资源耗尽的风险。
Executors返回的线程池对象的弊端如下:
好吧,昨天,我还通过ExecutorService executorService = Executors.newFixedThreadPool(200);
创建了一个线程池,看来以后要注意了。
具体分析以下【说明】中的内容,以FixedThreadPool为例,允许的请求队列长度为Integer.MAX_VALUE,可能会堆积大量的请求,从而导致OOM。
也就是说,我建了一个固定长度为200的线程池,当请求超过200时,线程池会新建一个队列queue,来储存阻塞的线程,而且new LinkedBlockingQueue()是一个没有大小限制的。规约的意思是当请求过多,每个任务执行较慢时,远超线程池的大小,会全部压到这个无界Queue中,这个队列queue会扛不住,有点道理。
public static ExecutorService newFixedThreadPool(int nThreads) {
return new ThreadPoolExecutor(nThreads, nThreads,
0L, TimeUnit.MILLISECONDS,
new LinkedBlockingQueue<Runnable>());
}
public class ThreadPoolTest {
public static void main(String[] args) throws IOException {
ExecutorService executorService = Executors.newFixedThreadPool(200);
for (int i = 0; i < 1000000; i++) {
Thread0926 thread = new Thread0926();
executorService.execute(thread);
}
}
private static Object lock = new Object();
public void increase() {
synchronized (lock) {
try {
String content = FileUtils.readFileToString(new File("H:\\CSDN\\08Typora文章\\Java高并发\\Java高并发编程实战1,那些年学过的锁.md"));
// 为了模拟OOM问题,歇20分钟
TimeUnit.MINUTES.sleep(20);
} catch (Exception e) {
}
}
}
}
果然,运行一段时间后,OOM了。
[09:49:07.412] [http-nio-48135-exec-1] [ERROR].[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
从日志可以看出,java.lang.OutOfMemoryError: unable to create new native thread
,OOM错误,无法新建本地线程。
由于代码中为了模拟OOM问题,读取一次超大文件,然后歇20分钟,也就是说会有大量的线程阻塞。
工作中,一般会根据程序的实际使用场景,评估线程池的几个重要参数:
设置拒绝策略,确保线程池的工作行为符合需求,一般都需要设置有界的工作队列和可控的线程数。
还有一点需要注意,当创建线程或线程池时,要指定有意义的线程名字,方便排查问题,定位错误代码位置。
上一篇:一个关于 i++ 和 ++i 的面试题打趴了所有人
哪吒多年工作总结:Java学习路线总结,搬砖工逆袭Java架构师。