Tomcat线程池,更符合大家想象的可扩展线程池
因由
说起线程池,大家可能受连接池的印象影响,天然的认为,它应该是一开始有core条线程,忙不过来了就扩展到max条线程,闲的时候又回落到core条线程,如果还有更高的高峰,就放进一个缓冲队列里缓冲一下。
有些整天只和SSH打交道的同学,可能现在还是这样认为的。
无情的现实就是,JDK只有两种典型的线程池,FixedPool 与 CachedPool:
- FixedPool固定线程数,忙不过来的全放到无限长的缓冲队列里。
- CachedPool,忙不过来时无限的增加临时线程,闲时回落,没有缓冲队列。
在Java ThreadPool的正确打开方式里,建议了如何设置,避免上面两句吓人的“无限”。但无论怎么配,都无法用现成的东西,配出文章一开始的想象图来。
但不得不说,这幅想象图还是比较美好的,特别对于偶有卡顿,偶有不可预测高峰的业务线程池来说。
当然,也有人说请求积压在最后的缓冲队列里不好控制,看具体业务场景了,缓冲队列也有不同的玩法(后详)。
原理
我们的同事老王,研究了一番ThreadPool的机制后,提出了自己实现队列的方式。碰巧,Tomcat也正是这么做的,比起Jetty完全自己写线程池,Tomcat基于JDK的线程池稍作定制,要斯文一些。
JDK线程池的逻辑很简单( 更详细描述还是见Java ThreadPool的正确打开方式 )
- 前core个请求,来一个请求就创建一个线程。
- 之后,把请求插入缓冲队列里让所有的线程去抢;如果插入失败则创建新线程。
- 如果达到max条线程了,抛出拒绝异常。
貌似控制的枢纽都在第2句那里--队列插入的结果。JDK也是通过使用LinkedBlockingQueue 与 特殊的SynchronousQueue,实现自己的控制效果。
那我可不可以自己封装一个Queue,在插入时增加以下逻辑呢?
- 如果当前有空闲线程等待接客,则把任务加入队列让孩儿们去抢。
- 如果没有空闲的了,总线程数又没到达max,那就返回false,让Executor去创建线程。
- 如果总线程数已达到max,则继续把任务加入队列缓冲一下。
- 如果缓冲队列也满了,抛出拒绝异常。
说白了就是这么简单。
Tomcat的实现
Tomcat的TaskQueue实现:
public class TaskQueue extends LinkedBlockingQueue {
@Override
public boolean offer(Runnable o) {
if (parent . getPoolSize() == parent . getMaximumPoolSize()) return super . offer(o);
if (parent . getSubmittedCount() < parent.getPoolSize()) return super . offer(o);
if (parent . getPoolSize() < parent . getMaximumPoolSize()) return false;
return super.offer(o);
}
}
非常简单的代码,唯一要说明的是,如何判断当前有没有空闲的线程等待接客。JDK的CachedPool是靠特殊的零长度的SynchronousQueue实现。而Tomcat则靠扩展Executor ,增加一个当前请求数的计数器,在execute()方法前加1,再重载afterExecute()方法减1,然后判断当前线程总数是否大于当前请求总数就知道有咩有围观群众。
更进一步
因为相信Tomcat这种百年老店,我们就不自己写这个池了,把Tomcat实现里一些无关需求剥掉即用。
但Tomcat就完美了吗?
首先,TaskQueue的offer()里,调用了executor.getPoolSize(),这是个有锁的函数,这是最遗憾的地方,在大家都在嫌线程池里一条队列锁得太厉害,像ForkJoinPool或Netty的设计都是一个线程一个队列时,这个有锁的函数相当碍眼。而且,最过分的是,Tomcat居然一口气调了三次(在Tomcat9 M9依然如此)。反复看了下,不求那么精准的话貌似一次就够了,真的有并发的变化的情况,executor里还有个处理RejectException,把任务重新放回队列的保险。
最后,说说缓冲队列的两种玩法:
一种是队列相对比较长,比如4096,主线程把任务丢进去就立刻返回了,如果队列满了就直接报拒绝异常。
一种是队列相对比较短的,比如512,如果满了,主线程就以queue.force(command, timeout)等在那里等队列有空,等到超时才报拒绝异常。
Tomcat的机制支持这两种玩法,自己设置就好。
文章可能还要修改,转载请保留原文链接,否则视为侵权:
http://calvin1978.blogcn.com/articles/tomcat-threadpool.html
Tomcat线程池,更符合大家想象的可扩展线程池的更多相关文章
- 原生线程池这么强大,Tomcat 为何还需扩展线程池?
前言 Tomcat/Jetty 是目前比较流行的 Web 容器,两者接受请求之后都会转交给线程池处理,这样可以有效提高处理的能力与并发度.JDK 提高完整线程池实现,但是 Tomcat/Jetty 都 ...
- Java:多线程,线程池,用Executors静态工厂生成常用线程池
一: newSingleThreadExecutor 创建一个单线程的线程池,以无界队列方式运行.这个线程池只有一个线程在工作(如果这个唯一的线程因为异常结束,那么会有一个新的线程来替代它.)此线程池 ...
- Java线程状态、线程start方法源码、多线程、Java线程池、如何停止一个线程
下面将依次介绍: 1. 线程状态.Java线程状态和线程池状态 2. start方法源码 3. 什么是线程池? 4. 线程池的工作原理和使用线程池的好处 5. ThreadPoolExecutor中的 ...
- 详解线程池的作用及Java中如何使用线程池
服务端应用程序(如数据库和 Web 服务器)需要处理来自客户端的高并发.耗时较短的请求任务,所以频繁的创建处理这些请求的所需要的线程就是一个非常消耗资源的操作.常规的方法是针对一个新的请求创建一个新线 ...
- 零基础学习java------day18------properties集合,多线程(线程和进程,多线程的实现,线程中的方法,线程的声明周期,线程安全问题,wait/notify.notifyAll,死锁,线程池),
1.Properties集合 1.1 概述: Properties类表示了一个持久的属性集.Properties可保存在流中或从流中加载.属性列表中每个键及其对应值都是一个字符串 一个属性列表可包含另 ...
- java并发:线程池、饱和策略、定制、扩展
一.序言 当我们需要使用线程的时候,我们可以新建一个线程,然后显式调用线程的start()方法,这样实现起来非常简便,但在某些场景下存在缺陷:如果需要同时执行多个任务(即并发的线程数量很多),频繁地创 ...
- SEO之HTML优化:让你的网站HTML代码更符合SEO规范
摘要HTML优化是网站内部优化的重点,可能对SEO新手来说,容易忽略.符合搜索引擎习惯的HTML代码是极利于SEO的,可以让你的网站获得更好的搜索引擎排名.如何制作一个标准的HTML网页,如何做HTM ...
- 第11章 Windows线程池(1)_传统的Windows线程池
第11章 Windows线程池 11.1 传统的Windows线程池及API (1)线程池中的几种底层线程 ①可变数量的长任务线程:WT_EXECUTELONGFUNCTION ②Timer线程:调用 ...
- 更符合面向对象的数据库操作方式-OrmLite
1. jar包下载 下载地址:http://ormlite.com/releases/,一般用core和android包即可. 如果使用的是android studio,也可以直接通过module s ...
随机推荐
- PHP工程师面临成长瓶颈
作为开发中应用最广泛的语言之一,PHP有着大量的粉丝,那么你是一名优秀的程序员吗?在进行自我修炼的同时,你是否想过面对各种各样的问题,我该如何突破自身的瓶颈,以便更好的发展呢?PHP工程师面临成长瓶颈 ...
- redhat6和ubuntu13.10在WMware player 下与Windows共享文件
Redhat下: 点击VMware的 setting -> vmware tools install mount /dev/cdrom /mnt/cdromcd /mnt/cdrom里面有一个v ...
- /usr/lib/libstdc++.so.6: version `GLIBCXX_3.4.15' not found错误的解决
升级cmake时,提示"Error when bootstrapping CMake:Problem while running initial CMake",第二次运行./boo ...
- 函数mem_pool_fill_free_list
/********************************************************************//** Fills the specified free l ...
- bzoj2351 2462
我没写hash,写了一些奇怪的做法,好像被hash随便操了…… 如果没有多测,那么这道题是白书上的例题 把询问矩阵当作a个模板串,建成一个ac自动机 把一开始的矩阵当作n个串放到自动机上匹配,找到a个 ...
- UVa 11178 (简单练习) Morley's Theorem
题意: Morley定理:任意三角形中,每个角的三等分线,相交出来的三个点构成一个正三角形. 不过这和题目关系不大,题目所求是正三角形的三个点的坐标,保留6位小数. 分析: 由于对称性,求出D点,EF ...
- 如何在Asp.Net WebApi接口中,验证请求参数中是否携带token标识!
[BasicAuthentication] public abstract class ApiControllerBase : ApiController { #region Gloal Proper ...
- hdu 4617 Weapon(叉积)
大一学弟表示刚学过高数,轻松无压力. 我等学长情何以堪= = 求空间无限延伸的两个圆柱体是否相交,其实就是叉积搞一搞 详细点就是求两圆心的向量在两直线(圆心所在的直线)叉积上的投影 代码略挫,看他的吧 ...
- 安装oracle XML Database 组件
近期部署项目数据库,编译包时遇到错误: PACKAGE CTG.CTG_CSB_COMMON 编译错误 错误:PLS-00201: identifier 'XMLDOM' must be dec ...
- spring3.0.5的aop使用
spring3.0.5开始支持jpa2.0了,但是最近笔者在使用他的的时候发现了3.0.5的包与2.5.5相比,有所精简.其他外部的包,我们需要自己下载. AOP必须的spring包 org.spri ...