• 关于springboot访问tomcat,线程http-nio-8080-exec的来源问题


    最近在看并发操作时候,例如jmeter进行接口压测(本地自己的springboot2的环境),发现一个有趣的现象,就是关于线程http-nio-8080-exec-1,http-nio-8080-exec-2等等的出现。但是这个线程数不管我的压测数是多少这个线程数不会超过10.抱着好奇的心去搜索了一下相关的文章,但是没有看到比较合适的。然后就只有自己去跟了一下源码。在此自己总结一下。

    两个问题:

    1、这个http-nio-8080-exec东西是怎么来的
    2、为什么这个线程数不超过10

    把这两个问题其实可以一起归为一个问题来跟代码进行解决:
    因为我们知道,一般在自定义线程或者线程池名称的时候,我们是可以自己去设置相关的线程名字的。这个名称的来源就是如下:

    在请求线程经过Tomcat时,会进入到org.apache.coyote.AbstractProtocol,这个方法,这是一个抽象类,可以看出其实这里就是在进行一个名称和端口号的拼接操作。getNamePrefix()的具体实现是在org.apache.coyote.http11.Http11NioProtocol

    private String getNameInternal() {
            StringBuilder name = new StringBuilder(getNamePrefix());
            name.append('-');
            if (getAddress() != null) {
                name.append(getAddress().getHostAddress());
                name.append('-');
            }
            int port = getPortWithOffset();
            if (port == 0) {
                // Auto binding is in use. Check if port is known
                name.append("auto-");
                name.append(getNameIndex());
                port = getLocalPort();
                if (port != -1) {
                    name.append('-');
                    name.append(port);
                }
            } else {
                name.append(port);
            }
            return name.toString();
        }
    
    @Override
        protected String getNamePrefix() {
            if (isSSLEnabled()) {
                return "https-" + getSslImplementationShortName()+ "-nio";
            } else {
                return "http-nio";
            }
        }
    
    • 1
    • 2
    • 3
    • 4
    • 5
    • 6
    • 7
    • 8
    • 9
    • 10
    • 11
    • 12
    • 13
    • 14
    • 15
    • 16
    • 17
    • 18
    • 19
    • 20
    • 21
    • 22
    • 23
    • 24
    • 25
    • 26
    • 27
    • 28
    • 29
    • 30
    • 31

    当创建连接的时候回进入到org.apache.tomcat.util.net.AbstractEndpoint,进入start()方法

     public final void start() throws Exception {
            if (bindState == BindState.UNBOUND) {
                bindWithCleanup();
                bindState = BindState.BOUND_ON_START;
            }
            startInternal();
        }
    
    • 1
    • 2
    • 3
    • 4
    • 5
    • 6
    • 7

    然后是startInternal(),在这个方法有一段

    if (getExecutor() == null) {
    createExecutor();
    }。也就是说,如果这个是一个新连接的话,会去新建一个线程。createExecutor()这个方法很重要算是核心实现了。

    public void createExecutor() {
            internalExecutor = true;
            TaskQueue taskqueue = new TaskQueue();
            TaskThreadFactory tf = new TaskThreadFactory(getName() + "-exec-", daemon, getThreadPriority());
            executor = new ThreadPoolExecutor(getMinSpareThreads(), getMaxThreads(), 60, TimeUnit.SECONDS,taskqueue, tf);
            taskqueue.setParent( (ThreadPoolExecutor) executor);
        }
    
    • 1
    • 2
    • 3
    • 4
    • 5
    • 6
    • 7

    从这里可以看到,这个创建连接的过程,就是通过网一个队列进行添加。这个getName()方法就是刚刚上面返回的http-nio-8080的那一部分。

    这里可以看到构造一个TaskThreadFactory类。构造方法如下

    public TaskThreadFactory(String namePrefix, boolean daemon, int priority) {
            SecurityManager s = System.getSecurityManager();
            group = (s != null) ? s.getThreadGroup() : Thread.currentThread().getThreadGroup();
            this.namePrefix = namePrefix;
            this.daemon = daemon;
            this.threadPriority = priority;
        }
    
    • 1
    • 2
    • 3
    • 4
    • 5
    • 6
    • 7

    重点看这个group,他是属于java.lang.ThreadGroup。构造方法中有这样一段代码

    private ThreadGroup() {     // called from C code
            this.name = "system";
            this.maxPriority = Thread.MAX_PRIORITY;
            this.parent = null;
        }
    
    • 1
    • 2
    • 3
    • 4
    • 5

    Thread.MAX_PRIORITY=10;换言之,就是在通过Tomcat的形式建立连接的时候,新建的连接对象都会有用到ThreadGroup,在ThreadGroup中就有限制最大的数卫10.所以会出现http-nio-8080-exec-9的情况也很正常了。

    先自我介绍一下,小编13年上师交大毕业,曾经在小公司待过,去过华为OPPO等大厂,18年进入阿里,直到现在。深知大多数初中级java工程师,想要升技能,往往是需要自己摸索成长或是报班学习,但对于培训机构动则近万元的学费,着实压力不小。自己不成体系的自学效率很低又漫长,而且容易碰到天花板技术停止不前。因此我收集了一份《java开发全套学习资料》送给大家,初衷也很简单,就是希望帮助到想自学又不知道该从何学起的朋友,同时减轻大家的负担。添加下方名片,即可获取全套学习资料哦

  • 相关阅读:
    ES6知识总结
    ICSFUZZ:操纵I/O、二进制代码重用以及插桩,来Fuzzing工业控制应用程序
    MySQL阅读网上MySQL文章有感的杂记
    记录一下自己涉及到的时间及金额方法的处理
    JUL 日志
    B. Find The Array
    强缓存与协商缓存
    ajax样式演示
    Linux【进程间通信】
    sqllabs通关笔记
  • 原文地址:https://blog.csdn.net/m0_52789121/article/details/126080963