Tomcat源码阅读之Connector启动

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线程也可以接受新的请求了,就这样把接受请求和处理请求的线程分开了。

  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值