design/sourcecode/课堂笔记nio

nio


BIO

tomcat 的 BIO 线程模型

  • 使用线程池(Executor)每次有新的线程接入,启动一个线程。每个线程里头有一个阻塞的 BIO(Acceptor)
    如有侵权,我是拷贝的
    参考下 Tomcat 的设计!
Connector 启动以后会启动一组线程用于不同阶段的请求处理过程。
  • Acceptor 线程组。用于接受新连接,并将新连接封装一下,选择一个 Poller 将新连接添加到 Poller 的事件队列中。
  • Poller 线程组。用于监听 Socket 事件,当 Socket 可读或可写等等时,将 Socket 封装一下添加到 worker 线程池的任务队列中。
  • worker 线程组。用于对请求进行处理,包括分析请求报文并创建 Request 对象,调用容器的 pipeline 进行处理。
Tomcat采用“IO线程与Worker线程通过队列解耦”类线程模型:
  • 有少数几个IO线程监听上游发过来的请求,并进行收发包(生产者)
  • 有一个或多个任务队列,作为IO线程与Worker线程异步解耦的数据传输通道(临界资源)
  • 有多个工作线程执行正真的任务(消费者)
    在这里插入图片描述
StandardServer 中开启 ServerSocket

Tomcat 只有一条线程负责套接字接收工作,所以它对每次接收处理的时间长短将很可能对整体性能产生影响。于是接收器所干的活都是非常少且简单的,仅仅维护了几个状态变量、流量控制闸门的累加操作、serverSocket的接收操作、设置接收到的socket的一些属性、将接收到的socket放入线程池以及一些异常处理。其他需要较长时间处理的逻辑就交给了线程池

  • APR
    APR
  • NIO
    NIO
// 在 NIO 模式中注册到 Poller 中
getPoller0().register(channel);
Acceptor 线程组 AprEndpoint
  • acceptors 数组
    /**
     * Threads used to accept new connections and pass them to worker threads.
     */
    protected Acceptor[] acceptors;
    
  • 如果达到最大线程数,就加入等待队列进行等待、默认最多开启 8 * 1024 个线程
    // ------------------------------------------------------------ Constructor
    
    public AprEndpoint() {
          
          
        // Need to override the default for maxConnections to align it with what
        // was pollerSize (before the two were merged)
        setMaxConnections(8 * 1024);
    }
    
  • 如果线程数达到最大值(默认 8 * 1024) 个,则等待
    protected void countUpOrAwaitConnection() throws InterruptedException {
          
          
        if (maxConnections==-1) return;
        LimitLatch latch = connectionLimitLatch;
        if (latch!=null) latch.countUpOrAwait();
    }
    
    • latch 里头使用 AbstractQueuedSynchronizer 计数(AQS则实现了对同步状态的管理,以及对阻塞线程进行排队,等待通知等等一些底层的实现处理)
    private class Sync extends AbstractQueuedSynchronizer {
          
          
        private static final long serialVersionUID = 1L;
    
        public Sync() {
          
          
        }
    
        @Override
        protected int tryAcquireShared(int ignored) {
          
          
            long newCount = count.incrementAndGet();
            if (!released && newCount > limit) {
          
          
                // Limit exceeded
                count.decrementAndGet();
                return -1;
            } else {
          
          
                return 1;
            }
        }
    
        @Override
        protected boolean tryReleaseShared(int arg) {
          
          
            count.decrementAndGet();
            return true;
        }
    }
    
Poller 线程组
  1. 等待中的 Socket 放入 poller[] 轮询数组中
  2. 指定间隔轮询
/**
 * Poll interval, in microseconds. The smaller the value, the more CPU the poller
 * will use, but the more responsive to activity it will be.
 */
 protected int pollTime = 2000;
// Wait for pollerTime before doing anything, so that the poller
// threads exit, otherwise parallel destruction of sockets which are
// still in the poller can cause problems
try {
    
    
    this.notify();
    this.wait(pollerCount * pollTime / 1000);
} catch (InterruptedException e) {
    
    
    // Ignore
}
  1. 将 Socket 封装到 SocketProcessor 中
    在这里插入图片描述
    在这里插入图片描述

  2. 将 SocketProcessor 提交到线程池,放入线程池的 workQueue 中
    在这里插入图片描述

worker 线程组

Handler

  • ConnectionHandler.process
Processor processor = connections.get(socket);
...
do {
    
    
	state = processor.process(wrapper, status);
	if (state == SocketState.UPGRADING) {
    
    
	....
	}
} while ( state == SocketState.UPGRADING);
if (state == ....) {
    
    
	...
}

Tomcat 概念(参考 how tomcat works)

Tomcat结构

处理 Socket

处理 Socket

Http 封装

Http 封装

多线程

多线程

Container

Container

Container模块

Container模块

Container-生命周期

Guess you like

Origin blog.csdn.net/u012296499/article/details/108192473