发布网友 发布时间:2024-10-24 07:42
共1个回答
热心网友 时间:2024-10-25 09:12
在默认的配置中tomcat采用Http11Protocol这个类来处理接收到的请求,
Http11Protocol又调用JIoEndpoint类实现对数据的接收,
JIoEndpoint类调用Http11Processor类实现对数据的解析。
当然还可以采用jno的方式接收请求,它的特点是处理并发请求效率高。原因是采用jno处理socket,不用为每个socket都分配线程。
因为jno中增加了选择器selector,它可以监视各个TCP连接,把准备好的TCP连接交给上层来处理。
这个还是得操作系统支持这种监视TCP连接的特性,在一个不支持此特定的操作系统上用jno也是枉然,
关于tomcat采用jno方式接收请求,还需用业余时间好好了解下。
具体说明一下JIoEndpoint类,它是怎样接收数据的。
在init()方法中
serverSocket = serverSocketFactory.createSocket(port, backlog, address);
创建serverSocket监听8080端口,说明了tomcat原来是用socket来接收请求的。
然后启动了Acceptor线程
这个线程的run方法:
Socket socket = serverSocketFactory.acceptSocket(serverSocket);
再看serverSocketFactory.acceptSocket的实现
public Socket acceptSocket(ServerSocket socket)
throws IOException {
return socket.accept();
}
一个典型的socket应用方式。serverSocket监听请求。
再接收到socket后,处理这个socket。这个socket就是浏览器或其他客户端与服务器建立的TCP连接。在这个连接中,传输了http协议格式的内容。
protected boolean processSocket(Socket socket) {
try {
if (executor == null) {
getWorkerThread().assign(socket);
} else {
executor.execute(new SocketProcessor(socket));
}
} catch (Throwable t) {
// This means we got an OOM or similar creating a thread, or that
// the pool and its queue are full
log.error(sm.getString("endpoint.process.fail"), t);
return false;
}
return true;
}
如果有jdk的线程池,就采用jdk自带的线程池处理它。如果没有就用JIoEndpoint类中实现的简易线程池处理。
默认的情况下没有配置jdk线程池,于是采用简易线程池处理。
简易线程池是JIoEndpoint类的内部类WorkerStack以及Worker实现的。
worker是一个线程,处理socket,同时加入了生产者
WorkerStack包含worker的数组以及对这个数组的处理。
getWorkerThread()是从WorkerStack中拿一个已经启动的worker线程出来。
重点讲述worker。
assign(socket) 调用worker的assign方法。
以下是worker的三个重要方法以及一个重要的变量available
protected boolean available = false;
synchronized void assign(Socket socket) {
// Wait for the Processor to get the previous Socket
while (available) {
try {
wait();
} catch (InterruptedException e) {
}
}
// Store the newly available Socket and notify our thread
this.socket = socket;
available = true;
notifyAll();
}
private synchronized Socket await() {
// Wait for the Connector to provide a new Socket
while (!available) {
try {
wait();
} catch (InterruptedException e) {
}
}
// Notify the Connector that we have received this Socket
Socket socket = this.socket;
available = false;
notifyAll();
return (socket);
}
public void run() {
// Process requests until we receive a shutdown signal
while (running) {
// Wait for the next socket to be assigned
Socket socket = await();
if (socket == null)
continue;
// Process the request from this socket
if (!setSocketOptions(socket) || !handler.process(socket)) {
// Close socket
try {
socket.close();
} catch (IOException e) {
}
}
// Finish up this request
socket = null;
recycleWorkerThread(this);
}
}
首先worker线程是运行着的,它执行到await()的时候,available为false,这时等待,不再继续执行。
调用assign的时候,available为false,不执行wait,方法继续执行,获得了一个socket,然后通知这个线程可以继续执行了。
于是在await()方法中,开始继续执行,返回Socket socket,run方法继续执行处理这个socket.
处理完毕后,再次调用await(),available为false,再次等待。直到再次assign唤醒它。
这样一个线程可以为多个socket服务。
先总结到这里。线程同步,如果写不好。就用jdk自带的线程池吧。