一、容器简化了程序员自身的多线程编程。
各种Web容器,如Tomcat,Resion,Jetty等都有自己的线程池(可在配置文件中配置),所以在客户端进行请求调用的时候,程序员不用针对Client的每一次请求,都新建一个线程。而容器会自动分配线程池中的线程,提高访问速度。
二、Tomcat线程池实现:
1、使用APR的Pool技术,使用了JNI。
Tomcat从5.5.17开始,为了提高响应速度和效率,使用了Apache Portable Runtime(APR)作为最底层,使用了APR中包含Socket、缓冲池等多种技术,性能也提高了。APR也是Apache HTTPD的最底层。
2、使用Java实现的Thread Pool。
ThreadPool默认创建了5个线程,保存在一个200维的线程数组中,创建时就启动了这些线程,当然在没有请求时,它们都处理“等待”状态(其实就是一个while循环,不停的等待notify)。如果有请求时,空闲线程会被唤醒执行用户的请求。
具体的请求过程是: 服务启动时,创建一个一维线程数组(maxThread=200个),并创建空闲线程(minSpareThreads=5个)随时等待用户请求。 当有用户请求时,调用 threadpool.runIt(ThreadPoolRunnable)方法,将一个需要执行的实例传给ThreadPool中。其中用户需要执行的 实例必须实现ThreadPoolRunnable接口。 ThreadPool 首先查找空闲的线程,如果有则用它运行要执行的ThreadPoolRunnable;
如果没有空闲线程并且没有超过maxThreads,就一次性创建 minSpareThreads个空闲线程;如果已经超过了maxThreads了,就等待空闲线程了。总之,要找到空闲的线程,以便用它执行实例。找到后,将该线程从线程数组中移走。 接着唤醒已经找到的空闲线程,用它运行执行实例(ThreadPoolRunnable)。 运行完ThreadPoolRunnable后,就将该线程重新放到线程数组中,作为空闲线程供后续使用。
由此可以看出,Tomcat的线程池实现是比较简单的,ThreadPool.java也只有840行代码。用一个一维数组保存空闲的线程,每次以一个较小步伐(5个)创建空闲线程并放到线程池中。使用时从数组中移走空闲的线程,用完后,再“归还”给线程池。
总结:
tomcat5.5.10以上版本开始支持apr,支持通过apache runtime module进行JNI调用,使用本地代码来加速网络处理。
如果不使用apr之前,Tomcat的Servlet线程池使用的是阻塞IO的模式,使用apr之后,线程池变成了 NIO的非阻塞模式,而且这种NIO还是使用了操作系统的本地代码,看tomcat文档上面的说法是,极大提升web处理能力,不再需要专门放一个web server处理静态页面了。
我自己直观的感受是,不用apr之前,你配置多少个等待线程,tomcat就会启动多少个线程挂起等待,使用apr以后,不管你配置多少,就只有几个NIO调度的线程,这一点你可以通过kill -3 PID,然后察看log得知。
假设不使用apr,可能端口的线程调度能力比较差,所以通过iptables进行端口转发,让两个端口去分担一个端口的线程调度,就有可能减少线程调度的并发,从而提高处理能力,减少资源消耗。
三、配置Tomcat线程池以使用高并发连接
1.打开共享的线程池:
<Service name="Catalina">
<!--The connectors can use a shared executor, you can define one or more named thread pools-->
<Executor name="tomcatThreadPool" namePrefix="catalina-exec-"
maxThreads="1000" minSpareThreads="50" maxIdleTime="600000"/>
默认前后是注释<!-- -->掉的,去掉就可以了。
重要参数说明:
name:共享线程池的名字。这是Connector为了共享线程池要引用的名字,该名字必须唯一。默认值:None;
namePrefix:在JVM上,每个运行线程都可以有一个name 字符串。这一属性为线程池中每个线程的name字符串设置了一个前缀,Tomcat将把线程号追加到这一前缀的后面。默认值:tomcat-exec-;
maxThreads:该线程池可以容纳的最大线程数。默认值:200;
maxIdleTime:在Tomcat关闭一个空闲线程之前,允许空闲线程持续的时间(以毫秒为单位)。只有当前活跃的线程数大于minSpareThread的值,才会关闭空闲线程。默认值:60000(一分钟)。
minSpareThreads:Tomcat应该始终打开的最小不活跃线程数。默认值:25。
threadPriority:线程的等级。默认是Thread.NORM_PRIORITY
2. 在Connector中指定使用共享线程池:
<Connector executor="tomcatThreadPool"
port="8080" protocol="HTTP/1.1"
connectionTimeout="20000"
redirectPort="8443"
minProcessors="5"
maxProcessors="75"
acceptCount="1000"/>
重要参数说明:
executor:表示使用该参数值对应的线程池;
minProcessors:服务器启动时创建的处理请求的线程数;
maxProcessors:最大可以创建的处理请求的线程数;
acceptCount:指定当所有可以使用的处理请求的线程数都被使用时,可以放到处理队列中的请求数,超过这个数的请求将不予处理。
BTW:我测试了一下,由于每次请求不再需要重新分配线程,系统响应速度还是有很明显的改善的。
相关推荐
它一开始就初始化了一定数量的线程,并通过ProcessQueuedItems方法保证异步执行进入池中的队列任务 这样在分配异步任务的时候,就省去了频繁去创建(new)一个线程 初始化线程池 添加线程操作 线程池事件 结束线程...
C++11 线程池 ThreadPool 单例 线程池,实现全局唯一。
c# 线程池的管理是通过ThreadPool
ThreadPool 线程池管理单元 带调用例子
对tomcat中线程池部门源码的解析比较详细
线程池threadpool_src,非常实用的线程池代码,好用方便!
线程池ThreadPool。
VC++实现的线程池代码,仅供参考,如果实际项目要用必须经过大量测试。
一个易于使用的C ++ 11线程池。 使用ThreadPool类对自由函数进行排队,并使用std :: for_each()和std :: transform()的并行版本。 可配置为仅用于标头或与库一起使用。 有许多用法示例。
主要为大家详细介绍了python线程池threadpool的实现,具有一定的参考价值,感兴趣的小伙伴们可以参考一下
Java版线程池ThreadPool
完善了些操作并使用的例子,如:。线程池 、。时钟线程池 、。线程池工作项、。线程池清理组、。(下面这两个还没弄 不过原理和前者相似)。线程池等待对象、。线程池IO对象、。@350246356。
java线程池threadpool简单范例,使用threadgroup类
线程池使用std :: thread和其他C ++ 11/14标准线程实用程序的C ++线程池。 易于使用,具有一些额外功能,可以进行更多控制。auto add(Func&& func, Args&&... args) 这是将作业添加到ThreadPool 。 接受要排队的可调...
linux下通过200行C代码实现简单线程池,附源代码和文档说明: 200行C代码实现简单线程池.doc threadpool.c
其中线程池管理器(ThreadPool Manager)的作用是创建、销毁并管理线程池,将工作线程放入线程池中;工作线程是一个可以循环执行任务的线程,在没有任务时进行等待;任务队列的作用是提供一种缓冲机制,将没有处理的...
保存的一份Linux下的线程池代码,使用C语言编写,另外添加了较详细的中文注释,附带测试代码,可以加深一些对线程池的认识,居家必备
DELPHI的线程池例子,可以直接使用.很方便.模仿.Net ThreadPool的线程池控件
zl_threadpool, Linux平台下C (C 98、C 03、C 11)实现的线程池