Java线程池与Tomcat线程池策略算法上的异同
Java线程池
如果当前运行的线程,少于corePoolSize,则创建一个新的线程来执行任务。
如果运行的线程等于或多于 corePoolSize,将任务加入 BlockingQueue。
如果 BlockingQueue 内的任务超过上限,则创建新的线程来处理任务。
如果创建的线程超出 maximumPoolSize,任务将被拒绝策略拒绝。
Tomcat线程池
如果当前运行的线程,少于corePoolSize,则创建一个新的线程来执行任务。
如果线程数大于 corePoolSize了,Tomcat 的线程不会直接把线程加入到无界的阻塞队列中,而是去判断submittedCount(已经提交线程数)是否等于 maximumPoolSize。
如果等于,表示线程池已经满负荷运行,不能再创建线程了,直接把线程提交到队列,
如果不等于,则需要判断,是否有空闲线程可以消费。
如果有空闲线程则加入到阻塞队列中,等待空闲线程消费。
如果没有空闲线程,尝试创建新的线程。(这一步保证了使用无界队列,仍然可以利用线程的 maximumPoolSize)。
如果总线程数达到 maximumPoolSize,则继续尝试把线程加入 BlockingQueue 中。
如果 BlockingQueue 达到上限(假如设置了上限),被默认线程池启动拒绝策略,tomcat 线程池会 catch 住拒绝策略抛出的异常,再次把尝试任务加入中 BlockingQueue 中。
再次加入失败,启动拒绝策略。
示例代码:
当 taskqueue.setParent(executor) 注释的时候,Tomcat 线程池运行的过程和 JDK 线程池的运行过程一样,运行的线程数只会是核心程序数 5。
当 taskqueue.setParent(executor) 取消注释的时候,Tomcat 线程池就会一直创建线程个数到 150 个,然后把剩下的任务提交到自定义的 TaskQueue 队列里面去。
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35
| public static void main(String[] args) throws InterruptedException { String namePrefix = "why不止技术-exec-"; boolean daemon = true; TaskQueue taskqueue = new TaskQueue(300); TaskThreadFactory tf = new TaskThreadFactory(namePrefix, daemon, Thread.NORM_PRIORITY); ThreadPoolExecutor executor = new ThreadPoolExecutor(5, 150, 60000, TimeUnit.MILLISECONDS, taskqueue, tf);
for (int i = 0; i < 300; i++) { try { executor.execute(() -> { logStatus(executor, "创建任务"); try { TimeUnit.SECONDS.sleep(2); } catch (InterruptedException e) { e.printStackTrace(); } }); } catch (Exception e) { e.printStackTrace(); } } Thread.currentThread().join(); }
private static void logStatus(ThreadPoolExecutor executor, String name) { TaskQueue queue = (TaskQueue) executor.getQueue(); System.out.println(Thread.currentThread().getName() + "-" + name + "-:" + "核心线程数:" + executor.getCorePoolSize() + "\t活动线程数:" + executor.getActiveCount() + "\t最大线程数:" + executor.getMaximumPoolSize() + "\t总任务数:" + executor.getTaskCount() + "\t当前排队线程数:" + queue.size() + "\t队列剩余大小:" + queue.remainingCapacity()); }
|