Tomcat中的connector负责将从客户端发出的请求封装成Request对象,再交由processor进行处理。
为了提高性能,connector内部实现了一个简单的多例模式来获取processor,在启动阶段,会有一定数量的processor提前被产生并保留在内存中,当需要时直接从内存中取。如果当前所有processor都被占用,则会继续产生新的processor并丢进内存缓存。
/**
* The current number of processors that have been created.
*/
private int curProcessors = 0;
/**
* The minimum number of processors to start at initialization time.
*/
protected int minProcessors = 5;
/**
* The maximum number of processors allowed, or <0 for unlimited.
*/
private int maxProcessors = 20;
/**
* The set of processors that have been created but are not currently
* being used to process a request.
*/
private Stack<HttpProcessor> processors = new Stack<HttpProcessor>();
/**
* Get Processor from stack if there still exist, or create new one
* if current processor number didn't more than max number.
* Otherwise, null will be returned.
*
* @return instance of HttpProcessor
*/
protected HttpProcessor getProcessor() {
synchronized (processors) {
if (processors.size() > 0) {
return processors.pop();
}
if ((maxProcessors > 0) && (curProcessors < maxProcessors)) {
return (newProcessor());
} else {
if (maxProcessors < 0) {
return (newProcessor());
} else {
return (null);
}
}
}
}
private HttpProcessor newProcessor() {
HttpProcessor processor = new HttpProcessor(this);
processor.start();
curProcessors++;
return processor;
}
public void recycle(HttpProcessor processor) {
processors.push(processor);
}
由于processor本身并不消耗资源,因此如此创建方式对性能并没有多大的提升。重点是对于每个processor实例,Tomcat将启动一个新的线程来处理socket,以此来或多更大的吞吐量。
以下是Tomcat如何启动多线程的processor并不断监听状态变化的方案。
HttpProcessor继承Runable接口,每当我们调用其start()方法时,都会启动一个新的线程:
public void start() {
Thread thread = new Thread(this);
thread.setDaemon(true);
thread.start();
}
public void run() {
while (!stopped) {
Socket socket = await();
if (socket == null) {
continue;
}
process(socket);
connector.recycle(this);
}
}
private synchronized Socket await() {
while (!available) {
try {
wait();
} catch (InterruptedException e) {
// Do nothing.
}
}
Socket socket = this.socket;
available = false;
notifyAll();
return socket;
}
当processor新线程启动时,它做了这样一系列的事情:
1. 等待其他线程通知,当某个通知到来时,验证available是否为false,如果为true,继续等待,否则进入第二步。
2. 获取实例变量socket的值,
3. 将available改成false。
4. 通知其他线程状态改变。
5. 对socket进行相应处理(process方法)。
6. connector资源回收该对象。
而在connector主线程中,是通过这种方式调用processor的:
HttpProcessor processor = getProcessor();
processor.assign(socket);
processor的assign方法如下:
/**
* The entry point of HttpProcessor. Assign an socket to the processor, it
* will start a new thread.
*
*
* @param socket
*/
public synchronized void assign(Socket socket) {
while(available) {
try {
wait();
} catch (InterruptedException e) {
// Do nothing.
}
}
this.socket = socket;
available = true;
notifyAll();
}
这个方法首先监听其他线程通知,一旦获得available为false了,便将socket值设置为新的值,并将available值改为true,最后通知其他线程。
assign方法和run方法运行在两个不同的线程中: connector主线程以及processor子线程。当主线程获得一个新的socket,就会assign给processor对象,并通知processor子线程。一旦通知完毕,主线程就返回继续监听其它socket。 而processor子线程收到通知后会对被assign的socket进行相应的处理。
通过这种方式,线程之间各司其职,获得了最大的性能提升。
分享到:
相关推荐
在深入探讨Tomcat 6.0中的线程池配置之前,有必要对线程池的基本概念进行简单回顾: - **线程池**:预先创建一定数量的线程,并存储在一个池子中,当有新的任务提交时,可以从池中取出一个空闲线程来执行该任务。 - ...
当队列满时,提交任务的线程会被阻塞,直到队列中有空闲位置。反之,当队列为空时,等待工作的线程会被阻塞,直到有新任务加入。这种设计使得线程池能够根据实际负载动态调整工作线程的数量。 TaskThread则封装了...
Java实现的线程池位于`tomcat-util.jar`中,初始化时创建了一个200维的线程数组,预创建了5个线程作为初始的空闲线程。这些线程在没有请求时处于等待状态,当收到请求时,线程池会分配一个空闲线程来处理请求。...
- **类结构**:程序主要由`CheckTomcat`类构成,其中包含了`checkTomcatIsAlive`方法用于检测Tomcat状态,以及`main`方法作为程序入口。 - **代码示例**: - **初始化配置**:在`main`方法中初始化`monitorurl`和`...
在Windows、Linux或Mac OS等不同操作系统上安装Tomcat的过程略有差异。通常,你需要下载对应平台的Tomcat二进制包,解压到合适的目录,然后根据系统环境变量配置`CATALINA_HOME`指向Tomcat的安装路径。在Windows上...
9. **JMX管理**:通过Java Management Extensions(JMX),开发者可以远程监控和管理Tomcat的运行状态,如查看线程池状态、内存使用情况等。 10. **性能优化**:优化Tomcat涉及调整线程池大小、缓存设置、减少上...
另一个可能的解决方案是使用第三方监控工具,例如Nagios、Zabbix或Prometheus等,这些工具能提供更全面的系统监控,包括CPU使用率、内存占用、网络状态以及Tomcat特定的指标,如线程池状态和HTTP请求响应时间。...
这份《Tomcat参考手册中文版chm》为开发者提供了全面的指引,无论是初学者还是有经验的管理员,都能从中获取所需的信息,解决在使用Tomcat过程中遇到的问题。通过深入学习和实践,我们可以更好地驾驭这个强大的Java...
8. **JMX (Java Management Extensions)**: Tomcat使用JMX暴露管理MBeans(Managed Beans),允许通过JMX代理远程监控和管理Tomcat服务器的状态,包括启动/停止应用、查看线程池状态、调整配置等。 9. **Clustering...
5. **部署Web应用**:在Tomcat中部署Web应用通常有以下几种方式: - 将应用的WAR文件放入`webapps`目录下,Tomcat会自动解压并部署。 - 使用`manager`应用通过HTTP上传WAR文件。 - 在Eclipse中右键点击项目,选择...
7. **日志和错误处理**: Tomcat的运行日志主要记录在`logs`目录下,如`catalina.out`、`host-manager.out`等,这对于排查问题和监控服务器状态非常重要。 8. **安全性**: Tomcat支持基本的身份验证和授权,如通过`...
- **死锁**:多线程应用程序中可能出现的死锁问题,也会使Tomcat服务陷入不可恢复的状态,最终导致服务自动关闭。 - **资源泄露**:如数据库连接、文件句柄等资源的不正确释放,随着时间推移,会逐渐消耗系统资源,...
5. **配置服务器**:在`conf/server.xml`文件中,你可以配置Tomcat的端口、线程池、连接器以及其他服务器设置。默认情况下,Tomcat使用8080端口监听HTTP请求。 6. **部署应用**:将你的Java Web应用程序(WAR文件)...
定期更新Tomcat到最新稳定版本有助于保持系统的安全性和稳定性。 总之,Apache Tomcat 8.0.53作为一个流行的Java Web服务器,是开发和部署Java应用的重要工具。理解和掌握其工作原理、配置与管理方法,对于任何Java...
8. **性能优化**:Tomcat可以通过调整线程池大小、内存分配、连接器设置等方式进行性能优化。例如,增加`maxThreads`参数可以处理更多并发请求。 9. **监控与管理**:通过内置的JMX(Java Management Extensions)...
10. **错误处理与日志**:Tomcat有详细的错误页面机制,可以根据不同的HTTP状态码返回相应的错误页面。Juli日志系统提供了灵活的日志配置,可以根据需求定制日志级别和格式。 《How Tomcat Works》这本书将帮助读者...
7. **性能优化**:Tomcat可以通过调整线程池大小、启用连接器优化、缓存管理等方式进行性能优化。例如,`conf/server.xml`中的`Connector`元素允许配置最大连接数、空闲超时等参数。 8. **部署应用**:Web应用程序...
在本文中,我们将深入探讨Tomcat 8.0的关键特性、安装与配置过程以及如何部署Web应用程序。 首先,Tomcat 8.0引入了Java EE 7的兼容性,这是它的一大改进。这意味着它可以支持包括WebSocket API、JAX-RS 2.0 ...
在处理请求时,Tomcat会从一个预先创建的线程池中取出线程来执行Servlet的service方法。这个线程池通常被称为" Coyote Connector ",负责接收并处理来自HTTP连接器的请求。 2. **线程池管理** 在Tomcat 5.5.17版本...
Tomcat支持三种运行模式:BIO、NIO 和 APR,每种模式都有其特点和适用场景: - **BIO (Blocking I/O)**:这是Tomcat默认的模式,每个连接都会占用一个独立的线程来处理请求,适用于低并发场景。但在高并发环境下,...