searchusermenu
  • 发布文章
  • 消息中心
点赞
收藏
评论
分享
原创

Tomcat线程模型分析

2023-10-31 02:20:16
49
0

1、Tomcat线程模型概述

  • tomcat介绍
    • connector服务实现接收客户端请求,然后将请求转向Servlet容器
    • 下面详细介绍Connector部分的线程模型
  • Tomcat线程模型
    • 这里以tomcat-embed-core:9.0.46为例
    • tcp三次握手后:
      • 作用:接受客户端请求,建立tcp连接
      • 逻辑:内核层:服务端收到客户端的 ACK 后,从半连接队列中取出连接放到全连接队列(Accept queue)中,服务端进入 ESTABLISHED 状态,等待应用层:ServerSocket执行accept()方法
    • Tomcat-Acceptor线程
      • 作用:执行accept()方法返回socket对象,告知Poller线程。
      • 逻辑:从Accept queue取出返回socket,创建一个Poller的OP_REGISTER事件,放入到Poller的SynchronizedQueue
    • Tomcat-Poller线程
      • 作用:负责监听socket的IO可读写事件
      • 逻辑:从Poller的SynchronizedQueue取出事件,并在Selector里注册socket的io可读写事件
    • Tomcat-ThreadPoolExecutor工作线程池
      • 作用:可读写的socket,交给线程池里的线程处理业务
      • 逻辑:字节流解析成http协议对应对象,并处理业务逻辑

2、Tomcat线程模型源码分析

2.1、Springboot主线程(启动Acceptor线程、Poller线程、worker线程池)

2.1.1、初始化NioEndpoint

  • 在Connector的startInternal()方法时,开始初始化ProtocalHandler,同时会初始化NioEndpoint(包含了初始化Acceptor线程、Poller线程和Worker线程池)
  • 在NioEndpoint类,初始化的时候,会调用startInternal()方法
  • 会启动Acceptor线程、Poller线程、初始化worker线程池

2.1.2. 初始化worker线程池Executor

  • 在NioEndpoint类,初始化的时候,会调用startInternal()方法,其中就会初始化worker线程池:createExecutor()
  • tomcat自己实现的taskQueue,是继承LinkedBlockingQueue,也是无界的,tomcat控制逻辑:在最前置acceptor就控制了总连接数,所以这个队列不会有OOM风险

2.2、Acceptor线程(接收到请求,将socket塞给Poller对象里面的同步队列)

2.3、 Poller线程(从Poller对象里的同步队列取Event)

从队列里取出Event,并且注册到selector

2.4、 Poller线程(处理IO读写事件,交给worker线程池)

  • Poller的run()方法一直循环,处理selector的IO读写事件,并交给tomcat-worker线程池处理
  • 创建socketProcessor对象,交给Executor线程池处理

2.5、 Worker线程池(处理业务)

2.5.1、Executor.execute(ScoketProcessor)线程池执行任务

  • 这里Tomcat的线程池继承jdk线程池,并根据web场景,做了些定制优化
    • jdk线程池逻辑:队列满了后,再创建非核心线程
    • Tomcat线程池逻辑:先创建非核心线程池,线程数达到最大线程数值,再进队列
    • 提交任务会计数:总共提交了多少任务
    • 同时还是交给父类ThreadPoolExecutor处理
    • tomcat的TaskQueue类的offer()方法的实现:当提交的任务数>线程池已有线程数,并且已有线程数<最大线程数,则不把任务加入队列,直接返回false(外层逻辑走到创建非核心线程数)

2.5.2、worker线程执行具体任务

  • Executor.execute(ScoketProcessor)传入的是SocketProcessor类,所以会调用该类的run()方法,执行业务逻辑(基本就是拿socket解析http协议,封装request和response给selevlet用)
    • NioEndpoint的内部类SocketProcessor,继承了SocketProcessorBase类,doRun()方法就是执行tomcat业务逻辑入口
  • ....执行一系列业务逻辑后
  • 写数据给客户端:是在servlet里就做了,例如springmvc的dispatchServlet

0条评论
作者已关闭评论
q****n
20文章数
0粉丝数
q****n
20 文章 | 0 粉丝
q****n
20文章数
0粉丝数
q****n
20 文章 | 0 粉丝
原创

Tomcat线程模型分析

2023-10-31 02:20:16
49
0

1、Tomcat线程模型概述

  • tomcat介绍
    • connector服务实现接收客户端请求,然后将请求转向Servlet容器
    • 下面详细介绍Connector部分的线程模型
  • Tomcat线程模型
    • 这里以tomcat-embed-core:9.0.46为例
    • tcp三次握手后:
      • 作用:接受客户端请求,建立tcp连接
      • 逻辑:内核层:服务端收到客户端的 ACK 后,从半连接队列中取出连接放到全连接队列(Accept queue)中,服务端进入 ESTABLISHED 状态,等待应用层:ServerSocket执行accept()方法
    • Tomcat-Acceptor线程
      • 作用:执行accept()方法返回socket对象,告知Poller线程。
      • 逻辑:从Accept queue取出返回socket,创建一个Poller的OP_REGISTER事件,放入到Poller的SynchronizedQueue
    • Tomcat-Poller线程
      • 作用:负责监听socket的IO可读写事件
      • 逻辑:从Poller的SynchronizedQueue取出事件,并在Selector里注册socket的io可读写事件
    • Tomcat-ThreadPoolExecutor工作线程池
      • 作用:可读写的socket,交给线程池里的线程处理业务
      • 逻辑:字节流解析成http协议对应对象,并处理业务逻辑

2、Tomcat线程模型源码分析

2.1、Springboot主线程(启动Acceptor线程、Poller线程、worker线程池)

2.1.1、初始化NioEndpoint

  • 在Connector的startInternal()方法时,开始初始化ProtocalHandler,同时会初始化NioEndpoint(包含了初始化Acceptor线程、Poller线程和Worker线程池)
  • 在NioEndpoint类,初始化的时候,会调用startInternal()方法
  • 会启动Acceptor线程、Poller线程、初始化worker线程池

2.1.2. 初始化worker线程池Executor

  • 在NioEndpoint类,初始化的时候,会调用startInternal()方法,其中就会初始化worker线程池:createExecutor()
  • tomcat自己实现的taskQueue,是继承LinkedBlockingQueue,也是无界的,tomcat控制逻辑:在最前置acceptor就控制了总连接数,所以这个队列不会有OOM风险

2.2、Acceptor线程(接收到请求,将socket塞给Poller对象里面的同步队列)

2.3、 Poller线程(从Poller对象里的同步队列取Event)

从队列里取出Event,并且注册到selector

2.4、 Poller线程(处理IO读写事件,交给worker线程池)

  • Poller的run()方法一直循环,处理selector的IO读写事件,并交给tomcat-worker线程池处理
  • 创建socketProcessor对象,交给Executor线程池处理

2.5、 Worker线程池(处理业务)

2.5.1、Executor.execute(ScoketProcessor)线程池执行任务

  • 这里Tomcat的线程池继承jdk线程池,并根据web场景,做了些定制优化
    • jdk线程池逻辑:队列满了后,再创建非核心线程
    • Tomcat线程池逻辑:先创建非核心线程池,线程数达到最大线程数值,再进队列
    • 提交任务会计数:总共提交了多少任务
    • 同时还是交给父类ThreadPoolExecutor处理
    • tomcat的TaskQueue类的offer()方法的实现:当提交的任务数>线程池已有线程数,并且已有线程数<最大线程数,则不把任务加入队列,直接返回false(外层逻辑走到创建非核心线程数)

2.5.2、worker线程执行具体任务

  • Executor.execute(ScoketProcessor)传入的是SocketProcessor类,所以会调用该类的run()方法,执行业务逻辑(基本就是拿socket解析http协议,封装request和response给selevlet用)
    • NioEndpoint的内部类SocketProcessor,继承了SocketProcessorBase类,doRun()方法就是执行tomcat业务逻辑入口
  • ....执行一系列业务逻辑后
  • 写数据给客户端:是在servlet里就做了,例如springmvc的dispatchServlet

文章来自个人专栏
云技术专栏
20 文章 | 1 订阅
0条评论
作者已关闭评论
作者已关闭评论
0
0