线程池

核心线程

当jdk里新new 一个线程池时,里面是没有线程的,还没有启动;jdk和tomcat线程池不同在于,tomcat会默认new就启动核心线程数;

通过看源码:当t1线程执行完任务,又来了一个新任务,t1不会继续捕获,而是转向t5

线程池中核心线程一直存活,是因为线程执行代码中有while循环一直查看阻塞队列中是否有任务,且当任务数>=核心线程数时,任务进入阻塞队列

当阻塞队列里也放满时,再新开线程,从阻塞队列中执行优先级最高的线程,最多只能创建设置的最大线程数个数

当线程池中任务执行完毕,多余的线程会随机删除只保留核心线程个数的线程,并不是只保留原始的核心线程

 

线程池的五种状态

Running:接收外部的新任务,也处理队列里的任务

(用户主动调用)Shutdown:不能再接收外部新的任务,但处理队列里的任务,执行方法为shutdown(),执行完队列里的任务之后,将线程池里的线程全部关闭;

(用户主动调用)Stop:不接受外部新任务,也不处理队列里的任务,执行方法为shutdownNow(),将线程池里的线程全部关闭;

Tidying:线程池里没有线程,队列里可能有任务;然后它会自动调用terminated()方法

Terminated:线程池终止所有线程的回调方法。

 

线程池为什么要使用阻塞队列?

当有新的任务提交到线程池中,而线程池中的活跃线程数达到核心线程数时,线程池会将后续的task提交到阻塞队列中:

线程池创建线程需要会获得mainlock全局锁,影响并发效率,阻塞队列可以很好的缓冲

如果新任务的到达速率超过了线程池的处理速率,那么新到来的请求将累加起来,这样会耗尽资源。

 

线程池四大拒绝策略

触发条件:当线程池中的线程数已经达到最大线程数且任务队列已满时,线程池会调用策略来处理无法执行的新任务。

abortPolicy(中止策略):线程池的默认拒绝策略,直接抛出异常,终止任务提交(不允许任务丢失时)

CallersRunPolicy(调用者运行策略):将被拒绝的任务返回给提交任务的线程执行,缓解缓冲池的压力,但可能会导致调用线程阻塞

DiscardPolicy(丢弃策略):直接丢弃,不会抛出异常(允许部分任务丢失)

DiscardOldestPolicy(丢弃最旧任务策略):丢弃阻塞队列中等待时间最长的任务,重新提交当前任务。

 

线程池的最佳核心线程如何确定?

分为三步:

理论预估:对于IO密集型任务,可以多开点线程,是CPU核数的2倍多;对于CPU密集型,一般维CPU个数+1

压测验证:得到不同并发情况下CPU使用率、响应时间、错误率等数据

监控动态调整:通过监控动态调整线程池的两大参数。

posted @ 2025-03-12 15:53  Dyj07  阅读(30)  评论(0)    收藏  举报