带你读《2022技术人的百宝黑皮书》——合理使用线程池以及线程变量(7)

简介: 带你读《2022技术人的百宝黑皮书》——合理使用线程池以及线程变量(7)

带你读《2022技术人的百宝黑皮书》——合理使用线程池以及线程变量(6)https://developer.aliyun.com/article/1340063?groupCode=taobaotech

image.png思 考 & 小 结                                                                          

Tomcat中通过自定义任务线程TaskThread实现对每个线程创建时间的记录;使用静态内部类WrappingRunna- ble对Runnable进行包装,用于对StopPooledThreadException异常类型的处理。

 

Tomcat为什么要自定义线程池和任务队列实现?                                                

JUC原生线程池在提交任务时,当工作线程数达到核心线程数后,继续提交任务会尝试将任务放入阻塞队列中, 只有当前运行线程数未达到最大设定值且在任务队列任务满后,才会继续创建新的工作线程来处理任务,因此JUC原生线程池无法满足Tomcat快速响应的诉求。

 

Tomcat为什么使用无界队列?

Tomcat在EndPoint中通过acceptCount和maxConnections两个参数来避免过多请求积压。其中maxCon- nections为Tomcat在任意时刻接收和处理的最大连接数,当Tomcat接收的连接数达到maxConnections时, Acceptor不会读取accept队列中的连接;这时accept队列中的线程会一直阻塞着,直到Tomcat接收的连接数小于maxConnections(maxConnections默认为10000,如果设置为-1,则连接数不受限制)。accept- Count为accept队列的长度,当accept队列中连接的个数达到acceptCount时,即队列满,此时进来的请求一  律被拒绝,默认值是100(基于Tomcat 8.5.43版本)。因此,通过acceptCount和maxConnections两个参数作用后,Tomcat默认的无界任务队列通常不会造成OOM。

/**
*Allows the server developer to specify the acceptCount (backlog) that
*should be used for server sockets. By default, this value
* is 100.
*/
private int acceptCount = 100;
private int maxConnections = 10000;

 

 

最佳实践

 

image.png避免用Executors 的创建线程池

 

 

 

image.png

 

Executors常用方法有以下几个:

 

newCachedThreadPool():创建一个可缓存的线程池,调用 execute 将重用以前构造的线程(如果线程可用)。如果没有可用的线程,则创建一个新线程并添加到线程池中。终止并从缓存中移除那些已有 60 秒钟未被使用的线程。CachedThreadPool适用于并发执行大量短期耗时短的任务,或者负载较轻的服务器;

newFiexedThreadPool(int nThreads):创建固定数目线程的线程池,线程数小于nThreads时,提交新的任务会创建新的线程,当线程数等于nThreads时,提交新的任务后任务会被加入到阻塞队列,正在执行的线程执行完毕后从队列中取任务执行,FiexedThreadPool适用于负载略重但任务不是特别多的场景,为了合理利用资源,需要限制线程数量;

newSingleThreadExecutor() 创建一个单线程化的 Executor,SingleThreadExecutor适用于串行执行任务的场景,每个任务按顺序执行,不需要并发执行;

newScheduledThreadPool(int corePoolSize) 创建一个支持定时及周期性的任务执行的线程池,多数情况下可用来替代 Timer 类。ScheduledThreadPool中,返回了一个ScheduledThreadPoolExecutor实例,而ScheduledThreadPoolExecutor实际上继承了ThreadPoolExecutor。从代码中可以看出,Scheduled- ThreadPool基于ThreadPoolExecutor,corePoolSize大小为传入的corePoolSize,maximumPoolSize大小为Integer.MAX_VALUE,超时时间为0,workQueue为DelayedWorkQueue。实际上Scheduled- ThreadPool是一个调度池,其实现了schedule、scheduleAtFixedRate、scheduleWithFixedDelay三个方法,可以实现延迟执行、周期执行等操作;

newSingleThreadScheduledExecutor() 创建一个corePoolSize为1的ScheduledThreadPoolExecutor;

newWorkStealingPool(int parallelism)返回一个ForkJoinPool实例,ForkJoinPool  主要用于实现“分而治之”的算法,适合于计算密集型的任务。

 

 

Executors类看起来功能比较强大、用起来还比较方便,但存在如下弊端:

 

 

FiexedThreadPool和SingleThreadPool任务队列长度为Integer.MAX_VALUE,可能会堆积大量的请求,从 而导致OOM;

CachedThreadPool和ScheduledThreadPool允许创建的线程数量为Integer.MAX_VALUE,可能会创建大量的线程,从而导致OOM;

 

使用线程时,可以直接调用 ThreadPoolExecutor 的构造函数来创建线程池,并根据业务实际场景来设置core-

PoolSize、blockingQueue、RejectedExecuteHandler等参数。

 

带你读《2022技术人的百宝黑皮书》——合理使用线程池以及线程变量(8)https://developer.aliyun.com/article/1340061?groupCode=taobaotech

相关文章
|
23天前
|
安全 Java 调度
Java语言多线程编程技术深度解析
Java语言多线程编程技术深度解析
291 1
|
24天前
|
缓存 监控 安全
Java的线程池和线程安全
Java的线程池和线程安全
|
4天前
|
Java
【技术瑜伽师】Java 线程:修炼生命周期的平衡之道,达到多线程编程的最高境界!
【6月更文挑战第19天】Java多线程编程犹如瑜伽修行,从创建线程开始,如`new Thread(Runnable)`,到启动线程的活跃,用`start()`赋予生命。面对竞争与冲突,借助同步机制保证资源访问的有序,如`synchronized`关键字。线程可能阻塞等待,如同瑜伽的静止与耐心。完成任务后线程终止,整个过程需密切关注状态变换,以求多线程间的和谐与平衡。持续修炼,如同瑜伽般持之以恒,实现高效稳定的多线程程序。
|
4天前
|
Java 开发者
【技术成长日记】Java 线程的自我修养:从新手到大师的生命周期修炼手册!
【6月更文挑战第19天】Java线程之旅,从新手到大师的进阶之路:始于创建线程的懵懂,理解就绪与运行状态的成长,克服同步难题的进阶,至洞悉生命周期的精通。通过实例,展示线程的创建、运行与同步,展现技能的不断提升与升华。
|
4天前
|
Java
【技术解码】Java线程的五味人生:新建、就绪、运行、阻塞与死亡的哲学解读!
【6月更文挑战第19天】Java线程生命周期如同人生旅程,经历新建、就绪、运行、阻塞至死亡五阶段。从`new Thread()`的诞生到`start()`的蓄势待发,再到`run()`的全力以赴,线程在代码中奔跑。阻塞时面临挑战,等待资源释放,最终通过`join()`或中断结束生命。线程的每个状态转变,都是编程世界与哲思的交汇点。
|
20天前
|
开发框架 监控 Java
【.NET Core】多线程之线程池(ThreadPool)详解(二)
【.NET Core】多线程之线程池(ThreadPool)详解(二)
31 3
|
20天前
|
SQL 开发框架 Java
【.NET Core】多线程之线程池(ThreadPool)详解(一)
【.NET Core】多线程之线程池(ThreadPool)详解(一)
24 2
|
23天前
|
安全 Java
JAVA语言中的多线程编程技术
JAVA语言中的多线程编程技术
|
23天前
|
存储 安全 Java
Java语言中的多线程编程技术深入解析
Java语言中的多线程编程技术深入解析
221 1
|
26天前
|
设计模式 安全 Java
Java 多线程系列Ⅳ(单例模式+阻塞式队列+定时器+线程池)
Java 多线程系列Ⅳ(单例模式+阻塞式队列+定时器+线程池)