欧美bbbwbbbw肥妇,免费乱码人妻系列日韩,一级黄片

springboot內置tomcat調優(yōu)并發(fā)線程數解析

 更新時間:2021年12月29日 10:01:59   作者:CRUD的W  
這篇文章主要介紹了springboot內置tomcat調優(yōu)并發(fā)線程數解析,具有很好的參考價值,希望對大家有所幫助。如有錯誤或未考慮完全的地方,望不吝賜教

前言

本文解析springboot內置tomcat調優(yōu)并發(fā)線程數的一些參數,并結合源碼進行分析

參數

線程池核心線程數

  • server.tomcat.min-spare-threads:該參數為tomcat處理業(yè)務的核心線程數大小,默認值為10

線程池最大線程數

  • server.tomcat.max-threads:該參數為tomcat處理業(yè)務的最大線程數大小,默認值為200,當對并發(fā)量有一點值時可以調大該參數

請求最大連接數

  • server.tomcat.max-connections:該參數為請求的最大連接數,默認值為10000,注意這個參數并不是設置在線程池上的,而是在tomcat的Acceptor類(專門處理連接的線程類)來控制的,結合源碼我們可以看到

在這里插入圖片描述

protected void countUpOrAwaitConnection() throws InterruptedException {
        if (maxConnections==-1) return;
        LimitLatch latch = connectionLimitLatch;
        if (latch!=null) latch.countUpOrAwait();
    }

可以看到當最大連接數滿了之后會進行等待

accept-count

server.tomcat.accept-count:這個參數實際上和tomcat沒有太大關系,默認值為100

我們先看下文檔的定義

/**
     * Allows the server developer to specify the acceptCount (backlog) that
     * should be used for server sockets. By default, this value
     * is 100.
     */
    private int acceptCount = 100;

這個參數是服務端創(chuàng)建ServerSocket時操作系統控制同時連接的最大數量的,服務端接收連接是通過accept()來的,accept()是非??斓模詀ccept-count的不需要太大,正常保持默認值100即可了,acceptCount這個參數和線程池無關,會被映射為backlog參數,是socket的參數,在源碼的使用是在NioEndpoint類的initServerSocket方法,在tomcat中的名字是backlog在springboot內置tomcat中名字沒有使用backlog而是使用acceptCount

serverSock.socket().bind(addr,getAcceptCount())
protected void initServerSocket() throws Exception {
        if (!getUseInheritedChannel()) {
            serverSock = ServerSocketChannel.open();
            socketProperties.setProperties(serverSock.socket());
            InetSocketAddress addr = (getAddress()!=null?new InetSocketAddress(getAddress(),getPort()):new InetSocketAddress(getPort()));
            // 核心代碼
            serverSock.socket().bind(addr,getAcceptCount());
        } else {
            // Retrieve the channel provided by the OS
            Channel ic = System.inheritedChannel();
            if (ic instanceof ServerSocketChannel) {
                serverSock = (ServerSocketChannel) ic;
            }
            if (serverSock == null) {
                throw new IllegalArgumentException(sm.getString("endpoint.init.bind.inherited"));
            }
        }
        serverSock.configureBlocking(true); //mimic APR behavior
    }

tomcat線程池處理機制

tomcat最終使用線程池來處理業(yè)務邏輯,java默認的線程池的規(guī)則:

核心線程數滿了則優(yōu)先放入隊列,當隊列滿了之后才會創(chuàng)建非核心線程來處理,那么tomcat是這樣做的嗎?

首先如果tomcat這樣做,那么當達到核心線程后后續(xù)任務就需要等待了,這顯然是不合理的,我們通過源碼來看下tomcat是如何處理的

在AbstractEndpoint的createExecutor創(chuàng)建了處理業(yè)務數據的線程池

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

主要是使用了TaskQueue隊列,ThreadPoolExecutor并不是jdk的,而是tomcat重寫的。

我們從線程池的處理方法execute看起

public void execute(Runnable command) {
        execute(command,0,TimeUnit.MILLISECONDS);
    }
public void execute(Runnable command, long timeout, TimeUnit unit) {
        submittedCount.incrementAndGet();
        try {
        	// 核心代碼
            super.execute(command);
        } catch (RejectedExecutionException rx) {
            if (super.getQueue() instanceof TaskQueue) {
                final TaskQueue queue = (TaskQueue)super.getQueue();
                try {
                    if (!queue.force(command, timeout, unit)) {
                        submittedCount.decrementAndGet();
                        throw new RejectedExecutionException("Queue capacity is full.");
                    }
                } catch (InterruptedException x) {
                    submittedCount.decrementAndGet();
                    throw new RejectedExecutionException(x);
                }
            } else {
                submittedCount.decrementAndGet();
                throw rx;
            }
        }
    }

又調用會jdk的execute了

public void execute(Runnable command) {
        if (command == null)
            throw new NullPointerException();
        
        int c = ctl.get();
		// 1、工作線程數小于核心線程數則添加任務,核心線程會處理
        if (workerCountOf(c) < corePoolSize) {
            if (addWorker(command, true))
                return;
            c = ctl.get();
        }
		// 2、工作線程不小于核心線程數,則放到workQueue隊列中
        if (isRunning(c) && workQueue.offer(command)) {
            int recheck = ctl.get();
            if (! isRunning(recheck) && remove(command))
                reject(command);
            else if (workerCountOf(recheck) == 0)
                addWorker(null, false);
        }
		// 3、否則添加任務,addWorker會進行創(chuàng)建線程
        else if (!addWorker(command, false))
            reject(command);
    }

從這里可以看到jdk線程池的機制,tomcat使用了自己的TaskQueue隊列,所以我們看代碼2處當核心線程用完了會調用隊列的offer方法

我們看TaskQueue的offer

public boolean offer(Runnable o) {
        //we can't do any checks
		// parent就是指線程池,沒有線程池則添加到隊列
        if (parent==null) return super.offer(o);
        //we are maxed out on threads, simply queue the object
		// 線程數量已經達到了最大線程數,那么只能添加到隊列
        if (parent.getPoolSize() == parent.getMaximumPoolSize()) return super.offer(o);
        //we have idle threads, just add it to the queue
		// 如果當前處理的任務數量小于當前線程池中線程的數量,那么任務放到線程池,即相當于馬上會有空閑線程來處理
        if (parent.getSubmittedCount()<=(parent.getPoolSize())) return super.offer(o);
        //if we have less threads than maximum force creation of a new thread
		// TODO 核心代碼,如果當前線程數量還沒有達到線程池最大線程池的數量,那么就直接創(chuàng)建線程,這里返回false
        if (parent.getPoolSize()<parent.getMaximumPoolSize()) return false;
        //if we reached here, we need to add it to the queue
		// 最后的策略,放到隊列
        return super.offer(o);
    }

可以看到當執(zhí)行offer時,不是直接放到隊列的,當線程池總線程數量還沒達到線程池最大線程數時會返回false,返回false時就會執(zhí)行線程池execute的代碼3處,執(zhí)行addWorker(command, false),也就開始創(chuàng)建新的線程來處理當前任務了

總結

tomcat主要通過使用自己的TaskQueue隊列來對線程池做出了不同的策略,也就是tomcat當線程數大于核心數時就會直接創(chuàng)建新的線程來處理,而不是放到隊列

想了解tomcat架構和處理流程的可以看這篇文章 www.dbjr.com.cn/article/233207.htm

以上為個人經驗,希望能給大家一個參考,也希望大家多多支持腳本之家。

相關文章

  • 簡單了解java等待喚醒機制原理及使用

    簡單了解java等待喚醒機制原理及使用

    這篇文章主要介紹了簡單了解java等待喚醒機制原理及使用,文中通過示例代碼介紹的非常詳細,對大家的學習或者工作具有一定的參考學習價值,需要的朋友可以參考下
    2019-12-12
  • java中transient關鍵字的作用解析

    java中transient關鍵字的作用解析

    這篇文章主要介紹了java中transient關鍵字的作用解析,日常業(yè)務中,為了安全起見,有些敏感信息我們不希望在網絡間被傳輸可以使用transient對字段進行修飾,不進行序列化,則返回獲取到的字段為null,需要的朋友可以參考下
    2023-11-11
  • kotlin基礎教程之類和繼承

    kotlin基礎教程之類和繼承

    這篇文章主要介紹了kotlin基礎教程之類和繼承的相關資料,需要的朋友可以參考下
    2017-05-05
  • Java Web三層架構的配置詳解

    Java Web三層架構的配置詳解

    這篇文章主要介紹了Java Web三層架構的配置方法,需要的朋友可以參考下
    2014-10-10
  • Scala中Array和List的區(qū)別說明

    Scala中Array和List的區(qū)別說明

    這篇文章主要介紹了Scala中Array和List的區(qū)別說明,具有很好的參考價值,希望對大家有所幫助。如有錯誤或未考慮完全的地方,望不吝賜教
    2021-10-10
  • 詳解一個簡單的Servlet容器的設計與實現

    詳解一個簡單的Servlet容器的設計與實現

    Servlet算是Java Web開發(fā)請求鏈路調用棧中底層的一個技術,而了解一個Servlet容器的實現有助于更好的理解JavaWeb開發(fā),所以下面就來看看如何設計與實現一個簡單的Servlet容器吧
    2023-07-07
  • springboot切面添加日志功能實例詳解

    springboot切面添加日志功能實例詳解

    在本篇文章里小編給大家整理的是關于springboot 切面添加日志功能的相關知識點內容,有需要的朋友們可以參考下。
    2019-09-09
  • java中volatile不能保證線程安全(實例講解)

    java中volatile不能保證線程安全(實例講解)

    下面小編就為大家?guī)硪黄猨ava中volatile不能保證線程安全(實例講解)。小編覺得挺不錯的,現在就分享給大家,也給大家做個參考。一起跟隨小編過來看看吧
    2017-09-09
  • 基于ElasticSearch Analyzer的使用規(guī)則詳解

    基于ElasticSearch Analyzer的使用規(guī)則詳解

    這篇文章主要介紹了基于ElasticSearch Analyzer的使用規(guī)則,具有很好的參考價值,希望對大家有所幫助。如有錯誤或未考慮完全的地方,望不吝賜教
    2021-07-07
  • JAVA WSIMPORT生成WEBSERVICE客戶端401認證過程圖解

    JAVA WSIMPORT生成WEBSERVICE客戶端401認證過程圖解

    這篇文章主要介紹了JAVA WSIMPORT生成WEBSERVICE客戶端401認證過程圖解,文中通過示例代碼介紹的非常詳細,對大家的學習或者工作具有一定的參考學習價值,需要的朋友可以參考下
    2020-10-10

最新評論