前言

详情可以查看 

可以看到线程池流程主要分为三步,第二步根据 queue#offer 方法返回结果,判断是否需要新建线程。

JDK 原生队列类型 LinkedBlockingQueueSynchronousQueue,两者实现逻辑不尽相同。

LinkedBlockingQueue

offer 方法内部将会根据队列是否已满作为判断条件。若队列已满,返回 false,若队列未满,则将任务加入队列中,且返回 true

SynchronousQueue

这个队列比较特殊,内部不会储存任何数据。若有线程将任务放入其中将会被阻塞,直到其他线程将任务取出。反之,若无其他线程将任务放入其中,该队列取任务的方法也将会被阻塞,直到其他线程将任务放入。

对于 offer 方法来说,若有其他线程正在被取方法阻塞,该方法将会返回 true。反之,offer 方法将会返回 false。

所以若想实现适合 io 密集型任务线程池,即优先新建线程处理任务,关键在于 queue#offer 方法。可以重写该方法内部逻辑,只要当前线程池数量小于最大线程数,该方法返回 false,线程池新建线程处理。

当然上述实现逻辑比较糙,下面我们就从 Tomcat 源码查看其实现逻辑。

Tomcat 扩展线程池

可以看到 Tomcat 线程池使用方法与普通的线程池差不太多。

接着我们查看一下 Tomcat 线程池核心方法 execute 的逻辑。

execute 方法逻辑比较简单,任务核心还是交给 Java 原生线程池处理。这里主要增加一个重试策略,如果原生线程池执行拒绝策略的情况,抛出 RejectedExecutionException 异常。这里将会捕获,然后重新再次尝试将任务加入到 TaskQueue ,尽最大可能执行任务。

这里需要注意 submittedCount 变量。这是 Tomcat 线程池内部一个重要的参数,它是一个 AtomicInteger 变量,将会实时统计已经提交到线程池中,但还没有执行结束的任务。也就是说 submittedCount 等于线程池队列中的任务数加上线程池工作线程正在执行的任务。 TaskQueue#offer将会使用该参数实现相应的逻辑。

接着我们主要查看 TaskQueue#offer 方法逻辑。

核心逻辑在于第三步,这里如果 submittedCount 小于当前线程池线程数量,将会返回 false。上面我们讲到 offer 方法返回 false,线程池将会直接创建新线程。

Dubbo 2.6.X 版本增加 EagerThreadPool,其实现原理与 Tomcat 线程池差不多,感兴趣的小伙伴可以自行翻阅。

折衷方法