带你读《2022技术人的百宝黑皮书》——合理使用线程池以及线程变量(5)https://developer.aliyun.com/article/1340064?groupCode=taobaotech
Tomcat自定义任务队列
在Tomcat中重新定义了一个阻塞队列TaskQueue,它继承于LinkedBlockingQueue。在Tomcat中,核心线程 数默认值为10,最大线程数默认为200,为了避免线程到达核心线程数后后续任务放入队列等待,Tomcat通过自 定义任务队列TaskQueue重写offer方法实现了核心线程池数达到配置数后线程的创建。
具体地,从线程池任务调度机制实现可知,当offer方法返回false时,线程池将尝试创建新新线程,从而实现任务的 快速响应。TaskQueue核心实现代码如下:
/** *As task queue specifically designed to run with a thread pool executor. The *task queue is optimised to properly utilize threads within a thread pool *executor. If you use a normal queue, the executor will spawn threads when *there are idle threads and you wont be able to force items onto the queue *itself. */ public class TaskQueue extends LinkedBlockingQueue<Runnable> { public boolean force(Runnable o, long timeout, TimeUnit unit) throws InterruptedException { if ( parent==null || parent.isShutdown() ) throw new RejectedExecutionException("Executor not running, can't force a command into the queue");
12 |
|
return super.offer(o,timeout,unit); //forces the item onto the queue, to be used if the task is rejected |
13 |
|
} |
14 |
|
|
15 |
|
@Override |
16 |
|
public boolean offer(Runnable o) { |
17 |
|
// 1. parent为线程池,Tomcat中为自定义线程池实例 |
18 |
|
//we can't do any checks |
19 |
|
if (parent==null) return super.offer(o); |
20 |
|
// 2. 当线程数达到最大线程数时,新提交任务入队 |
21 |
|
//we are maxed out on threads, simply queue the object |
22 |
|
if (parent.getPoolSize() == parent.getMaximumPoolSize()) return super.offer(o); |
23 |
|
// 3. 当提交的任务数小于线程池中已有的线程数时,即有空闲线程,任务入队即可 |
24 |
|
//we have idle threads, just add it to the queue |
25 |
|
if (parent.getSubmittedCount()<=(parent.getPoolSize())) return super.offer(o); |
26 |
|
// 4. 【关键点】如果当前线程数量未达到最大线程数,直接返回false,让线程池创建新线程 |
27 |
|
//if we have less threads than maximum force creation of a new thread |
28 |
|
if (parent.getPoolSize()<parent.getMaximumPoolSize()) return false; |
29 |
|
// 5. 最后的兜底,放入队列 |
30 |
|
//if we reached here, we need to add it to the queue |
31 |
|
return super.offer(o); |
32 |
|
} |
33 |
} |
|
Tomcat自定义任务线程
Tomcat中通过自定义任务线程TaskThread实现对每个线程创建时间的记录;使用静态内部类WrappingRunna- ble对Runnable进行包装,用于对StopPooledThreadException异常类型的处理。
/** * A Thread implementation that records the time at which it was created. * */ public class TaskThread extends Thread { private final long creationTime; public TaskThread(ThreadGroup group, Runnable target, String name) { super(group, new WrappingRunnable(target), name); this.creationTime = System.currentTimeMillis(); } /** *Wraps a {@link Runnable} to swallow any {@link StopPooledThreadException} *instead of letting it go and potentially trigger a break in a debugger. */ private static class WrappingRunnable implements Runnable { private Runnable wrappedRunnable; WrappingRunnable(Runnable wrappedRunnable) { this.wrappedRunnable = wrappedRunnable; } @Override public void run() { try { wrappedRunnable.run(); } catch(StopPooledThreadException exc) { //expected : we just swallow the exception to avoid disturbing //debuggers like eclipse's log.debug("Thread exiting on purpose", exc); } } } }
带你读《2022技术人的百宝黑皮书》——合理使用线程池以及线程变量(7)https://developer.aliyun.com/article/1340062?groupCode=taobaotech