Tomcat源码阅读之Connector启动
来源:互联网 发布:下载游戏的软件 编辑:程序博客网 时间:2024/06/07 00:58
Tomcat的主要功能简单概括起来就是接收请求,处理请求,返回结果,而接收请求和返回结果的过程都需要Connector组件参与。那么我们以Http/1.1对应的连接器为例,看下Connector组件启动过程的源码。Connector组件启动的主要逻辑在JIoEndpoint类的start方法中。
public void start() throws Exception { // Initialize socket if not done before if (!initialized) { init(); } if (!running) { running = true; paused = false; // Create worker collection if (executor == null) { workers = new WorkerStack(maxThreads); } // Start acceptor threads for (int i = 0; i < acceptorThreadCount; i++) { Thread acceptorThread = new Thread(new Acceptor(), getName() + "-Acceptor-" + i); acceptorThread.setPriority(threadPriority); acceptorThread.setDaemon(daemon); acceptorThread.start(); } } }
方法中首先实例化一个WorkerStack对象,该对象负责管理work线程,类中有个work数组负责存放work线程,在实例化WorkerStack对象的时候会将这个数组的大小初始化为200,WorkerStack对象利用这个数组实现了一个栈的数据结构。work线程的作用是负责处理请求,因此我们可以得出这样一个结论:Tomcat中处理请求的线程数量默认的最大是200。work线程中除了run方法外还有两个比较重要的方法,分别是assign和await。
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);
关于这两个方法的作用我们待会儿再讲,接着看start方法。方法中通过一个for循环启动Acceptor线程,顾名思义Acceptor线程的作用就是接收请求。Tomcat启动了多少个线程来接收请求呢?答案是一个,前面我们有说到,在执行JIoEndpoint类的init方法的时候将acceptorThreadCount的值设置为1,表示启动接收线程的数量。那么问题来了,Tomcat只启动了一个接收线程性能会不会有问题,能快速的响应多个请求吗?其实不然,接收线程设置成一个是没有问题的,因为它只负责接收,收到请求后就扔给work线程去处理,然后Acceptor继续接收请求。相比于接收请求,处理过程将更会耗时,这就是为什么work线程有多个,而Acceptor线程只有一个的原因了。
Acceptor线程接收请求并将请求交给work线程处理的逻辑都在run方法中。首先通过Socket socket = serverSocketFactory.acceptSocket(serverSocket)
这样一句代码使socket处于监听状态,监听端口默认是8080,此时程序处于阻塞状态,直到有请求到来。当接收到请求后调用processSocket方法先创建并启动work线程,然后调用work线程的assign方法。`work线程启动过程中,会执行run方法里的代码:
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); } }
方法中首先执行await方法,由于此时available的值为false,因此work线程会处于等待状态。此时会调用work线程的assign方法,因为available的值为false,因此assign方法不会处于进入wait方法,并且将带有请求信息的socket对象传递给this.socket,设置available的值,最重要的一点是唤醒所有等待的线程。因此assign和await方法的执行顺序是先执行await阻塞程序等待socket的到来,然后执行assign方法传递socket对象,唤醒work线程。assign执行完之后,因为await方法而处于等待状态的work线程被唤醒了,并且获取到了从Acceptor线程那边传递过来的socket对象,而socket对象中又有请求信息,也就是说Acceptor线程将处理请求的任务给了work线程,而Acceptor线程也可以接受新的请求了,就这样把接受请求和处理请求的线程分开了。
- Tomcat源码阅读之Connector启动
- Tomcat源码阅读之Connector设计与实现
- Tomcat 源码阅读(四)Connector
- tomcat源码分析之connector
- Tomcat源码之Connector (1)
- Tomcat源码分析之Connector
- Tomcat源码之Connector (1)
- Tomcat源码分析之Connector
- Tomcat源码之Connector(1)
- Tomcat源码之Connector(2)
- Tomcat源码阅读之Engine启动过程
- Tomcat源码阅读之Host启动
- Tomcat源码阅读之Context启动
- Tomcat源码阅读系列(四)Connector连接器
- Tomcat源码阅读之Bootstrap启动流程与classLoader设计
- tomcat源码:Connector模块
- tomcat源码浅析--connector
- Tomcat源码阅读之过滤器
- Windows环境Mycat数据库分库分表中间件部署
- 文章标题
- 跟我一起写操作系统(二)——史上最简单的内核
- Java IO流汇总
- 匿名类
- Tomcat源码阅读之Connector启动
- C++ STL学习——stack
- 黑白棋(博弈论)
- 复习图片加载ImageLoader
- Android中获取系统内存信息以及进程信息-----ActivityManager的使用(一)
- VIJOS 1128 DFS+MR 判素数
- 类加载过程
- call forwarding
- xshell使用以及配置