首页 > 其他分享 >Tomcat 三大核心线程组件Acceptor、Poller 和 Executor&为什么tomcat 要把Acceptor单独抽出来,不和read、write一起放到事件循环里?

Tomcat 三大核心线程组件Acceptor、Poller 和 Executor&为什么tomcat 要把Acceptor单独抽出来,不和read、write一起放到事件循环里?

时间:2025-01-06 18:29:46浏览次数:3  
标签:tomcat Tomcat 处理 线程 Poller 连接 Acceptor

4a87b891769f482a8890648389622392.png

在 Tomcat 的架构中,AcceptorPoller 和 Executor 是处理网络连接和请求的重要组件。 

Acceptor

Acceptor 是 Tomcat 中负责接受新连接的组件。它的主要职责包括:

  • 监听端口:Acceptor 在线程中监听一个特定的端口,等待客户端连接请求。
  • 接受连接:当有新的连接请求到达时,Acceptor 负责接受该连接。
  • 交给处理器:Acceptor 将接受到的连接交给连接处理器(如处理 HTTP 请求的线程池)进行具体的请求处理。

这种设计使得 Tomcat 能够高效地处理大量并发连接,因为接受连接的操作与实际处理请求的操作是分离的。

Poller

Poller 是 Tomcat 中负责监控已打开的连接的组件。它的主要职责包括:

  • 监控事件:Poller 线程会监控已打开的连接,等待这些连接上发生的事件(如读取数据、写入数据等)。
  • 事件分发:当连接上有事件发生时,Poller 会将这些事件分发给适当的处理器进行处理。

Poller 使用了非阻塞 I/O(如 Java NIO)的机制,这使得它能够高效地处理大量并发连接,而不会因为等待 I/O 操作而阻塞线程。

Executor

Executor 是 Tomcat 中用于管理线程池的组件。它的主要职责包括:

  • 线程池管理:Executor 维护一个线程池,用于处理各种任务(如请求处理、连接处理等)。
  • 任务调度:当有新的任务需要处理时,Executor 会从线程池中分配一个线程来执行该任务。

通过使用线程池,Tomcat 能够更好地管理系统资源,避免了频繁创建和销毁线程的开销,从而提高了性能。

工作流程

  1. 接受连接:Acceptor 线程监听端口,接受新的客户端连接。
  2. 注册事件:接受到连接后,Acceptor 将连接注册到 Poller 中,等待事件发生。
  3. 事件监控:Poller 线程监控连接上的事件,如数据可读或可写。
  4. 事件处理:当事件发生时,Poller 将事件分发给处理器(如请求处理器)进行处理。
  5. 请求处理:处理器从 Executor 的线程池中获取线程来处理请求。

Tomcat 关键源码:

98f91c1e36f74421a1ebdfb75106362e.png

Poller 核心作用就是 Nio的时间循环,处理读写事件

b9101215808340599f701c729a8435f8.png

 

一个简单的NIO DEMO:

import java.io.IOException;
import java.net.InetSocketAddress;
import java.nio.ByteBuffer;
import java.nio.channels.SelectionKey;
import java.nio.channels.Selector;
import java.nio.channels.ServerSocketChannel;
import java.nio.channels.SocketChannel;
import java.util.Iterator;
import java.util.Set;

public class NioServer {
    private Selector selector;
    private ByteBuffer buffer = ByteBuffer.allocate(256);

    public static void main(String[] args) throws IOException {
        new NioServer().startServer();
    }

    public void startServer() throws IOException {
        // 打开 Selector 和 ServerSocketChannel
        selector = Selector.open();
        ServerSocketChannel serverSocket = ServerSocketChannel.open();
        
        // 绑定端口并配置为非阻塞模式
        serverSocket.bind(new InetSocketAddress("localhost", 8080));
        serverSocket.configureBlocking(false);
        
        // 注册 ServerSocketChannel 到 Selector,监听连接事件
        serverSocket.register(selector, SelectionKey.OP_ACCEPT);
        
        System.out.println("Server started on port 8080");

        while (true) {
            // 阻塞直到有事件发生
            selector.select();

            // 获取所有发生事件的 SelectionKey
            Set<SelectionKey> selectedKeys = selector.selectedKeys();
            Iterator<SelectionKey> iterator = selectedKeys.iterator();

            while (iterator.hasNext()) {
                SelectionKey key = iterator.next();

                if (key.isAcceptable()) {
                    register(selector, serverSocket);
                }

                if (key.isReadable()) {
                    answerWithEcho(buffer, key);
                }

                iterator.remove();
            }
        }
    }

    private void register(Selector selector, ServerSocketChannel serverSocket) throws IOException {
        // 接受客户端连接并配置为非阻塞模式
        SocketChannel client = serverSocket.accept();
        client.configureBlocking(false);

        // 注册 SocketChannel 到 Selector,监听读事件
        client.register(selector, SelectionKey.OP_READ);
        System.out.println("Client connected: " + client.getRemoteAddress());
    }

    private void answerWithEcho(ByteBuffer buffer, SelectionKey key) throws IOException {
        SocketChannel client = (SocketChannel) key.channel();
        client.read(buffer);
        buffer.flip();
        client.write(buffer);
        buffer.clear();
    }
}

为什么 Tomcat  Acceptor 单独抽取出来了

对比tomcat 源码和常规NIO写法,发现 tomcat  接受网络连接 accept()单独抽出来了,没有放到事件循环里,为什么要这么做呢?

 Tomcat 中,Acceptor 是一个专门用于接受新连接的组件。将 Acceptor 独立出来有以下几个原因:

  1. 解耦和职责单一

    • Acceptor 的唯一职责是监听并接受新的客户端连接,这种职责单一的设计使得代码更加清晰、易于维护和扩展。
    • 通过将接受连接与处理连接逻辑分离,Tomcat 可以更高效地管理连接的生命周期。
  2. 提高并发处理能力

    • Acceptor 独立运行在自己的线程中,可以持续不断地接受新的连接,而不会被具体的请求处理所阻塞。
    • 这使得 Tomcat 能够在高并发场景下高效地处理大量的并发连接。
  3. 负载均衡和资源管理

    • 通过独立的 Acceptor 线程,Tomcat 可以更好地控制和分配系统资源。例如,可以限制 Acceptor 的数量以防止系统资源被耗尽。
    • 独立的 Acceptor 还可以为不同的连接类型(如 HTTP 和 HTTPS)提供不同的处理机制和策略。
  4. 提高响应速度

    • 独立的 Acceptor 可以立即处理新的连接请求,而无需等待当前请求的处理完成,从而提高了服务器的响应速度。
  5. 容错和稳定性

    • 如果请求处理出现问题(如长时间阻塞或异常),Acceptor 线程不会受到影响,可以继续接受新的连接,从而提高了系统的稳定性和容错能力。

 

Tomcat Executor 线程池:

eba32a176ac9433fa7b6c91cb12f7327.png

 

在 Tomcat 中,ThreadPoolExecutor 是一个关键组件,用于管理线程池,以便高效地处理并发请求。通过合理地利用ThreadPoolExecutor,Tomcat 能够提高资源利用率,减少线程创建和销毁的开销,从而提升服务器的性能和响应速度。

  1. 线程池的基本概念

    • 线程复用:线程池中的线程可以被复用,避免了频繁创建和销毁线程的开销。
    • 任务队列:任务队列用于存储等待执行的任务,当有可用线程时,会从队列中取出任务执行。
    • 核心线程数:线程池会维护一定数量的核心线程,即使这些线程处于空闲状态,它们也不会被销毁。
    • 最大线程数:线程池允许的最大线程数,如果任务量超过核心线程数时,会创建新的线程,但不会超过这个最大值。
    • 存活时间:当线程池中线程数量超过核心线程数时,多余的线程在空闲时间超过设定的存活时间后会被终止。
  2. ThreadPoolExecutor 的工作流程

    • 任务提交:当有新任务提交时,首先判断核心线程池是否已满,如果未满则创建新线程执行任务。
    • 任务排队:如果核心线程池已满,则将任务加入任务队列。
    • 线程扩展:当任务队列已满且线程池未达到最大线程数时,会创建新的线程执行任务。
    • 任务拒绝:如果任务队列已满且线程池已达到最大线程数,则会根据拒绝策略处理新提交的任务。

 

 

标签:tomcat,Tomcat,处理,线程,Poller,连接,Acceptor
From: https://blog.csdn.net/zfj321/article/details/144952392

相关文章

  • dockerfile实现tomcat以及java的war包自动部署.240108
    1.下载jdk和tomcatwgethttps://dlcdn.apache.org/tomcat/tomcat-8/v8.5.93/bin/apache-tomcat-8.5.93.tar.gzwgethttps://repo.huaweicloud.com/java/jdk/8u202-b08/jdk-8u202-linux-x64.tar.gz2.vimDockerfileFROMcentos:latestMAINTAINERAmadeus#nowaddj......
  • MongoDB或TOMCAT定时切割日志文件的脚本.250103
    MongoDB用过一段时间后,日志较大,需要定时进行日志切割。一、切割bash:splitlogmongo.sh#!/bin/bashlog_dir="/home/mongodb/logs"file_name="/home/mongodb/logs/mongodb.log"if[!-d$log_dir];thenmkdir-p$log_dirfiif[!-f$file_name];thentouch$file_name......
  • RockyLinux 9.5 MySQL5.7_二进制方式+jdk1.8+tomcat9+jpress
    安装MySQL5.7#cd/opt#yuminstall-ywget#wgethttps://cdn.mysql.com/archives/mysql-5.7/mysql-5.7.10-linux-glibc2.5-x86_64.tar.gz#tar-xvfmysql-5.7.10-linux-glibc2.5-x86_64.tar.gz-bash:tar:commandnotfound#yuminstall-ytar#tar-xvfmysql-5.7.10......
  • 常见中间件漏洞(tomcat,weblogic,jboss,apache)
    先准备好今天要使用的木马文件使用哥斯拉生成木马压缩成zip文件改名为war后缀一:Tomcat1.1CVE-2017-12615环境搭建cdvulhub-master/tomcat/CVE-2017-12615docker-composeup-d1.首页抓包,修改为PUT方式提交发送shell.jsp和木马内容201创建成功2.......
  • Tomcat解析
    架构图核心功能Tomcat是Apache开源的轻量级JavaServlet容器,其中一个Server(Tomcat实例)可以管理多个Service(服务),一个Service包含多个Connector和一个Engine,负责管理请求到应用的整个流程。Tomcat要实现的两个核心功能:处理Socket连接,负责网络字节流与Request、Response请求......
  • 《docker基础篇:8.Docker常规安装简介》包括:docker常规安装总体步骤、安装tomcat、安装
    @目录8.Docker常规安装简介8.1docker常规安装总体步骤8.2安装tomcat8.3安装mysql8.3.1dockerhub上面查找mysql镜像8.3.2从dockerhub上(阿里云加速器)拉取mysql镜像到本地标签为5.78.3.3使用mysql5.7镜像创建容器(也叫运行镜像)简单版实战版8.4安装redis8.5安装nginx本人......
  • Linux 虚拟机环境安装(jdk/mysql/redis/tomcat/nginx/挂载)
    =================================================================准备工作=================================================================yuminstallwgetyuminstall-ygcc-c++pcrepcre-develzlibzlib-developensslopenssl-develyuminstallchkconfi......
  • 【详解】解决Eclipse发布到Tomcat丢失依赖jar包的问题
    目录解决Eclipse发布到Tomcat丢失依赖jar包的问题问题原因解决方案自动化构建考虑结论代码概述代码的基本组成示例代码(Python)解决Eclipse发布到Tomcat丢失依赖jar包的问题在Web开发过程中,使用Eclipse作为IDE并将项目发布到Tomcat服务器上是常见的操作。然而,有时在......
  • Tomcat与Finereport部署新得
    Tomcat算是Fine与html的中间件,用来解析jsp文件编译成网页。受中小型企业广泛使用。 Tomcat部署方案有很多(详情工程部署方案选择)。Tomcat(中间件)、JDK(java)、Fine(网页报表)、Linux(系统)之间要和谐共处需要下一番功夫。我实践两种部署下面两种部署方式部署包部署一键部署,自带JD......
  • springboot项目启动和部署: 自带tomcat
    springboot项目启动:springboot内部嵌入了tomcat,在spring-boot-starter-web里可以找到,在这里插入图片描述这样在研发过程中就不在需要tomcat服务器,并且springboot项目在打完jar之后,可以直接启动也不需要另外的本地tomcat。也就是说拿到springboot项目jar之后,完全可以在一台只有j......