国产 无码 综合区,色欲AV无码国产永久播放,无码天堂亚洲国产AV,国产日韩欧美女同一区二区

Tomcat線程池原理(上篇:初始化原理)

這篇具有很好參考價值的文章主要介紹了Tomcat線程池原理(上篇:初始化原理)。希望對大家有所幫助。如果存在錯誤或未考慮完全的地方,請大家不吝賜教,您也可以點擊"舉報違法"按鈕提交疑問。

前言

在Java Web的開發(fā)過程中,Tomcat常用的web容器。SpringBoot之前,我們用的是單獨的 Tomcat,SpringBoot時代,嵌入了Tomcat。

在Jdk中,JUC內(nèi)有線程框架,以及可以自定義參數(shù)配置的 TreadPoolExecutor。Tomcat內(nèi)也實現(xiàn)了自己的線程池。

所謂線程池,是被用來處理傳入的 HTTP 請求的。
當客戶端發(fā)送請求時,Tomcat 會從線程池中獲取一個可用的線程來處理該請求。處理完請求后,線程將返回線程池,并在下一個請求到來時再次被重用。

究其原因,是JUC內(nèi)的線程池不符合Tomcat的使用場景。

  • Jdk中的線程池,是cpu密集型(也就是偏計算,處理完了可以去隊列再取任務)
  • Tomcat的應用場景,卻大多是IO密集型的。(也就是要求IO盡量不要阻塞,任務先處理,實在處理不了了,再進阻塞隊列)

下圖是JUC中線程池處理任務的流程:
Tomcat線程池原理(上篇:初始化原理),java源碼,web框架學習,tomcat,線程池原理,tomcat線程池初始化

與JUC中明顯不同的一點是,Tomcat為了處理IO,減少阻塞的情況,
本系列文章就是專門探討Tomcat中線程池的原理,分為上下兩篇,本文是上篇,主要介紹Tomcat中線程池的初始化原理。

本系列文章基于SpringBoot2.7.6,其內(nèi)嵌的tomcat版本是9.0.69。
同系列文章:Tomcat線程池原理(下篇:工作原理)

正文

本系列文章核心內(nèi)容是Tomcat的線程池原理,因此在畫圖,文字描述時會忽略部分不涉及的內(nèi)容。

一、從啟動腳本開始分析

使用過Tomcat的同學都知道,我們單獨的啟動tomcat時,是從腳本入手的。

啟動tomcat , 需要調(diào)用 bin/startup.bat (在linux 目錄下 , 需要調(diào)用 bin/startup.sh)
在startup.bat 腳本中, 調(diào)用了catalina.bat。
在catalina.bat 腳本文件中,調(diào)用了BootStrap 中的main方法。
后續(xù)的操作如下圖:
Tomcat線程池原理(上篇:初始化原理),java源碼,web框架學習,tomcat,線程池原理,tomcat線程池初始化
簡而言之,就是逐級的 init()start()。
而本文的關注點,就是 ProtocolHandlerstart(),也就是圖中的最后一步。

二、ProtocolHandler 的啟動原理

Tomcat線程池原理(上篇:初始化原理),java源碼,web框架學習,tomcat,線程池原理,tomcat線程池初始化
關鍵在于 EndPointstart()。

而在Tomcat 中,會執(zhí)行到 AbstractEndPointstart()。具體代碼如下:

public final void start() throws Exception {
    if (bindState == BindState.UNBOUND) {
        bindWithCleanup();
        bindState = BindState.BOUND_ON_START;
    }
    startInternal();
}


public abstract void startInternal() throws Exception;

也就是說真正的啟動方法是AbstractEndPoint 子類實現(xiàn)的startInternal()。

三、AbstractEndPoint 的啟動原理

在Tomcat中,有3個AbstractEndPoint的子類。
在8.5/9.0版本中,使用的是其中的 NioEndPoint類。
本文就使用默認的 NioEndPoint 進行分析。

接第二小節(jié), NioEndPoint 在執(zhí)行startInternal()時,會判斷是否存在線程池,如果沒有,會創(chuàng)建默認的線程池。對應代碼如下:

@Override
public void startInternal() throws Exception {

    if (!running) {
        running = true;
        paused = false;

        if (socketProperties.getProcessorCache() != 0) {
            processorCache = new SynchronizedStack<>(SynchronizedStack.DEFAULT_SIZE,
                    socketProperties.getProcessorCache());
        }
        if (socketProperties.getEventCache() != 0) {
            eventCache = new SynchronizedStack<>(SynchronizedStack.DEFAULT_SIZE,
                    socketProperties.getEventCache());
        }
        if (socketProperties.getBufferPool() != 0) {
            nioChannels = new SynchronizedStack<>(SynchronizedStack.DEFAULT_SIZE,
                    socketProperties.getBufferPool());
        }

        // 如果沒自定義線程池,則創(chuàng)建默認工作線程池
        if (getExecutor() == null) {
            createExecutor();
        }

        initializeConnectionLatch();

        // Start poller thread
        poller = new Poller();
        Thread pollerThread = new Thread(poller, getName() + "-Poller");
        pollerThread.setPriority(threadPriority);
        pollerThread.setDaemon(true);
        pollerThread.start();

        startAcceptorThread();
    }
}

四、創(chuàng)建默認線程池

根據(jù)第三小節(jié)的分析,在沒自定義線程池,或者配置線程池時,會自動創(chuàng)建一個線程池。代碼如下:

    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);
    }

注意,ThreadPoolExecutor 不是JUC中的線程池了,其是Tomcat自己實現(xiàn)的線程池。

五、參數(shù)配置原理

日常工作中,總會遇到需要自己制定Tomcat線程池參數(shù)的情況。這一小節(jié)就來說明一下。
在Tomcat中,TomcatWebServerFactoryCustomizer 負責配置自定義參數(shù)。

在自動配置類 EmbeddedWebServerFactoryCustomizerAutoConfiguration 中配置了如下內(nèi)容:

@Configuration(proxyBeanMethods = false)
@ConditionalOnClass({ Tomcat.class, UpgradeProtocol.class })
public static class TomcatWebServerFactoryCustomizerConfiguration {

	@Bean
	public TomcatWebServerFactoryCustomizer tomcatWebServerFactoryCustomizer(Environment environment,
		ServerProperties serverProperties) {
			return new TomcatWebServerFactoryCustomizer(environment, serverProperties);
	}
}

5.1 常規(guī)的參數(shù)配置

普通的參數(shù)配置可以參考ServerProperties 中的內(nèi)容。

# Tomcat連接數(shù)相關參數(shù)
# 最大連接數(shù),默認8192,一般要大于(tomcat.threads.max + tomcat.accept-count)
server.tomcat.max-connections=300
# 當所有工作線程都被占用時,新的連接將會放入等待隊列中的最大容量,默認100
server.tomcat.accept-count=50

# Tomcat線程池相關參數(shù)
# 最大線程池大小,默認200
server.tomcat.threads.max=200
# 最小工作空閑線程數(shù)(核心線程數(shù)),默認10
server.tomcat.threads.min-spare=12

5.2 自定義線程池

如果普通的參數(shù)配置,不能滿足你的需求,則需要自定義線程池。

定義自己的類,繼承 TomcatWebServerFactoryCustomizer ,然后重寫customize即可。
核心思路是,在AbstractProtocol 中設置線程池。

以下是我的示例:

package org.feng.demos.web;

import org.apache.coyote.AbstractProtocol;
import org.apache.coyote.ProtocolHandler;
import org.apache.tomcat.util.threads.TaskQueue;
import org.apache.tomcat.util.threads.TaskThreadFactory;
import org.apache.tomcat.util.threads.ThreadPoolExecutor;
import org.springframework.boot.autoconfigure.web.ServerProperties;
import org.springframework.boot.autoconfigure.web.embedded.TomcatWebServerFactoryCustomizer;
import org.springframework.boot.web.embedded.tomcat.ConfigurableTomcatWebServerFactory;
import org.springframework.core.env.Environment;
import org.springframework.stereotype.Component;

import java.util.concurrent.TimeUnit;

/**
 * 自定義tomcat線程池
 *
 * @author feng
 */
@Component
public class MyTomcatWebServerFactoryCustomizer extends TomcatWebServerFactoryCustomizer {

    public MyTomcatWebServerFactoryCustomizer(Environment environment, ServerProperties serverProperties) {
        super(environment, serverProperties);
    }

    @Override
    public void customize(ConfigurableTomcatWebServerFactory factory) {
        super.customize(factory);

        // 自定義tomcat線程池
        System.out.println("自定義tomcat線程池--start");

        // 自定義tomcat線程池
        factory.addConnectorCustomizers((connector) -> {
            ProtocolHandler handler = connector.getProtocolHandler();
            if (handler instanceof AbstractProtocol) {
                AbstractProtocol protocol = (AbstractProtocol) handler;
                TaskQueue taskqueue = new TaskQueue();
                TaskThreadFactory tf = new TaskThreadFactory("feng" + "-exec-", true, 5);
                ThreadPoolExecutor threadPoolExecutor = new ThreadPoolExecutor(5, 10, 60L, TimeUnit.SECONDS, taskqueue, tf);
                protocol.setExecutor(threadPoolExecutor);
                taskqueue.setParent(threadPoolExecutor);
            }
        });

        System.out.println("自定義tomcat線程池--end");
    }
}

5.3 測試自定義線程

定義如下方法:

// http://127.0.0.1:8080/hello?name=lisi
@RequestMapping("/hello")
@ResponseBody
public String hello(@RequestParam(name = "name", defaultValue = "unknown user") String name) {
    System.out.println("當前線程名:" + Thread.currentThread().getName());
    return "Hello " + name;
}

調(diào)用時,控制臺打?。?br>Tomcat線程池原理(上篇:初始化原理),java源碼,web框架學習,tomcat,線程池原理,tomcat線程池初始化文章來源地址http://www.zghlxwxcb.cn/news/detail-835635.html

到了這里,關于Tomcat線程池原理(上篇:初始化原理)的文章就介紹完了。如果您還想了解更多內(nèi)容,請在右上角搜索TOY模板網(wǎng)以前的文章或繼續(xù)瀏覽下面的相關文章,希望大家以后多多支持TOY模板網(wǎng)!

本文來自互聯(lián)網(wǎng)用戶投稿,該文觀點僅代表作者本人,不代表本站立場。本站僅提供信息存儲空間服務,不擁有所有權,不承擔相關法律責任。如若轉載,請注明出處: 如若內(nèi)容造成侵權/違法違規(guī)/事實不符,請點擊違法舉報進行投訴反饋,一經(jīng)查實,立即刪除!

領支付寶紅包贊助服務器費用

相關文章

  • canal server初始化源碼分析

    canal server初始化源碼分析

    在開始之前,我們可以先了解下, canal 配置方式 ManagerCanalInstanceGenerator: 基于manager管理的配置方式,實時感知配置并進行server重啟 SpringCanalInstanceGenerator:基于本地spring xml的配置方式,對于多instance的時候,不便于擴展,一個instance一個xml配置 canal 配置文件 canal.properties ?

    2024年01月19日
    瀏覽(27)
  • SpringMVC源碼解析——DispatcherServlet初始化

    SpringMVC源碼解析——DispatcherServlet初始化

    在Spring中,ContextLoaderListener只是輔助功能,用于創(chuàng)建WebApplicationContext類型的實例,而真正的邏輯實現(xiàn)其實是在DispatcherServlet中進行的,DispatcherServlet是實現(xiàn)Servlet接口的實現(xiàn)類。Servlet是一個JAVA編寫的程序,此程序是基于HTTP協(xié)議的,在服務端運行的(如Tomcat),是按照Servlet規(guī)范

    2024年02月03日
    瀏覽(24)
  • UE4 源碼解析----引擎初始化流程

    UE4 源碼解析----引擎初始化流程

    ? ?在研究UE4的源碼過程中著實不理解的地方有很多,今天給大家分享一下UE4引擎的初始化流程。 C++的函數(shù)入口都是Main() 函數(shù)入口,UE4也是一樣,EngineSourceRuntimeLaunchPrivate Windows函數(shù)入口 ?引擎入口函數(shù)為:GuardedMain UE4所有相關的代碼都在游戲循環(huán)函數(shù)中,在Launch.cpp中,寫

    2024年02月06日
    瀏覽(22)
  • 【STM32&RT-Thread零基礎入門】 5. 線程創(chuàng)建應用(線程創(chuàng)建、刪除、初始化、脫離、啟動、睡眠)

    【STM32&RT-Thread零基礎入門】 5. 線程創(chuàng)建應用(線程創(chuàng)建、刪除、初始化、脫離、啟動、睡眠)

    硬件:STM32F103ZET6、ST-LINK、usb轉串口工具、4個LED燈、1個蜂鳴器、4個1k電阻、2個按鍵、面包板、杜邦線 本章主要講線程的工作機制和管理方法,通過實例講解如何使用多線程完成多任務開發(fā)。 RT-Thread用線程控制塊來描述和管理一個線程,一個線程對應一個線程控制塊。線程控

    2024年02月12日
    瀏覽(26)
  • 【源碼解析】聊聊SpringBean是如何初始化和創(chuàng)建

    【源碼解析】聊聊SpringBean是如何初始化和創(chuàng)建

    我們知道通過類進行修復不同的屬性,比如單例、原型等,而具體的流程是怎么樣的呢,這一篇我們開始從源碼的視角分析以下。 在刷新容器中有一個方法,其實就是 Bean創(chuàng)建的過程。 而BeanFactory中 preInstantiateSingletons是初始化所有的bean對象的核心流程。 而這里通過去遍歷所

    2024年02月05日
    瀏覽(23)
  • 『手撕 Mybatis 源碼』06 - Mapper 代理方式初始化

    『手撕 Mybatis 源碼』06 - Mapper 代理方式初始化

    首先修改一下 SqlSession 獲取代理對象方式,即通過 getMapper() 來拿到動態(tài)代理對象 修改 sqlMapConfig.xml 引入配置文件的方式 把 UserMapper.xml 放到和 com.itheima.mapper.UserMapper 同一個目錄,同時修改一下命名空間,然后就可以學習 MyBatis 的代理方式 問題 package name=“com.itheima.mapper”/

    2024年02月09日
    瀏覽(24)
  • SpringBoot 源碼分析初始化應用上下文(1)-createApplicationContext

    SpringBoot 源碼分析初始化應用上下文(1)-createApplicationContext

    前言:springBoot的版本是? 2.2.4.RELEASE 問題切入:為什么叫做上下文對象呢?上下文對象,就是當前應用環(huán)境下的一個集合 初始化(創(chuàng)建)上下文對象主要看上面注釋那行,即: 接著看下 createApplicationContext() 這個方法的實現(xiàn) 截圖: 代碼: ?接著看下AnnotationConfigServletWebServerApp

    2024年02月08日
    瀏覽(17)
  • Spring 填充屬性和初始化流程源碼剖析及擴展實現(xiàn)

    Spring 填充屬性和初始化流程源碼剖析及擴展實現(xiàn)

    在上一篇博文 講解 Spring 實例化的不同方式及相關生命周期源碼剖析 介紹了 Spring 實例化的不同方式,本文主要圍繞實例化過后對象的填充屬性和初始化過程進行詳細流程剖析 回顧前言知識,doCreateBean-createBeanInstance,通過 Supplier 接口、FactoryMethod、構造函數(shù)反射 invoke,創(chuàng)建

    2024年02月06日
    瀏覽(28)
  • Java的初始化塊

    三種初始化數(shù)據(jù)域的方法: 在構造器中設置值 在聲明中賦值 初始化塊(initialization block) 在一個類的聲明中,可以包含多個代碼塊。只要構造類的對象,這些塊就會被執(zhí)行。 在上面這個示例中,無論使用哪個構造器構造對象,id 域都在對象初始化塊中被初始化。首先運行初

    2023年04月27日
    瀏覽(28)
  • 從內(nèi)核源碼看 slab 內(nèi)存池的創(chuàng)建初始化流程

    從內(nèi)核源碼看 slab 內(nèi)存池的創(chuàng)建初始化流程

    在上篇文章 《細節(jié)拉滿,80 張圖帶你一步一步推演 slab 內(nèi)存池的設計與實現(xiàn) 》中,筆者從 slab cache 的總體架構演進角度以及 slab cache 的運行原理角度為大家勾勒出了 slab cache 的總體架構視圖,基于這個視圖詳細闡述了 slab cache 的內(nèi)存分配以及釋放原理。 slab cache 機制確實比

    2023年04月12日
    瀏覽(100)

覺得文章有用就打賞一下文章作者

支付寶掃一掃打賞

博客贊助

微信掃一掃打賞

請作者喝杯咖啡吧~博客贊助

支付寶掃一掃領取紅包,優(yōu)惠每天領

二維碼1

領取紅包

二維碼2

領紅包