关于Tomcat的一些关键参数

目录

  • Tomcat参数总览
    • 设置位置
  • 参数分析
    • Tomcat内部类maxConnections属性
    • Tomcat内部类的acceptCount
    • Tomcat有几个Acceptor线程
    • Tomcat的工作线程池

Tomcat参数总览

package org.springframework.boot.autoconfigure.web;
/**
* 
*  {@link ConfigurationProperties @ConfigurationProperties} for a web server (e.g. * port
 * and path settings).
*/
@ConfigurationProperties(prefix = "server", ignoreUnknownFields = true)
public class ServerProperties {
	/**
	 * Server HTTP port.
	 */
	private Integer port;


	/**
	 * Maximum size of the HTTP message header.
	 */
	private DataSize maxHttpHeaderSize = DataSize.ofKilobytes(8);

	private final Tomcat tomcat = new Tomcat();

	/**
	 * Tomcat properties.
	 */
	public static class Tomcat {
		
		/**
		 * Thread related configuration.
		 */
		private final Threads threads = new Threads();
		/**
		 * Tomcat base directory. If not specified, a temporary directory is used.
		 */
		private File basedir;
		/**
		 * Maximum size of the form content in any HTTP post request.
		 */
		private DataSize maxHttpFormPostSize = DataSize.ofMegabytes(2);

		/**
		 * Maximum amount of request body to swallow.
		 */
		private DataSize maxSwallowSize = DataSize.ofMegabytes(2);
		/**
		 * Maximum number of connections that the server accepts and processes at any
		 * given time. Once the limit has been reached, the operating system may still
		 * accept connections based on the "acceptCount" property.
		 */
		private int maxConnections = 8192;

		/**
		 * Maximum queue length for incoming connection requests when all possible request
		 * processing threads are in use.
		 */
		private int acceptCount = 100;
				/**
		 * Maximum number of idle processors that will be retained in the cache and reused
		 * with a subsequent request. When set to -1 the cache will be unlimited with a
		 * theoretical maximum size equal to the maximum number of connections.
		 */
		private int processorCache = 200;
		/**
		 * Amount of time the connector will wait, after accepting a connection, for the
		 * request URI line to be presented.
		 */
		private Duration connectionTimeout;
	}
	/**
		 * Tomcat thread properties.
		 */
		public static class Threads {

			/**
			 * Maximum amount of worker threads.
			 */
			private int max = 200;

			/**
			 * Minimum amount of worker threads.
			 */
			private int minSpare = 10;

		}
}

设置位置

public class TomcatWebServerFactoryCustomizer
		implements WebServerFactoryCustomizer<ConfigurableTomcatWebServerFactory>, Ordered {

		@Override
		public void customize(ConfigurableTomcatWebServerFactory factory) {
			ServerProperties properties = this.serverProperties;
			ServerProperties.Tomcat tomcatProperties = properties.getTomcat();
			PropertyMapper propertyMapper = PropertyMapper.get();
			propertyMapper.from(tomcatProperties::getBasedir).whenNonNull().to(factory::setBaseDirectory);
			propertyMapper.from(tomcatProperties::getBackgroundProcessorDelay).whenNonNull().as(Duration::getSeconds)
					.as(Long::intValue).to(factory::setBackgroundProcessorDelay);
			customizeRemoteIpValve(factory);
			ServerProperties.Tomcat.Threads threadProperties = tomcatProperties.getThreads();
			
			propertyMapper.from(threadProperties::getMax).when(this::isPositive)
					.to((maxThreads) -> customizeMaxThreads(factory, threadProperties.getMax()));
			propertyMapper.from(threadProperties::getMinSpare).when(this::isPositive)
					.to((minSpareThreads) -> customizeMinThreads(factory, minSpareThreads));
			propertyMapper.from(this.serverProperties.getMaxHttpHeaderSize()).whenNonNull().asInt(DataSize::toBytes)
					.when(this::isPositive)
					.to((maxHttpHeaderSize) -> customizeMaxHttpHeaderSize(factory, maxHttpHeaderSize));
			propertyMapper.from(tomcatProperties::getMaxSwallowSize).whenNonNull().asInt(DataSize::toBytes)
					.to((maxSwallowSize) -> customizeMaxSwallowSize(factory, maxSwallowSize));
			propertyMapper.from(tomcatProperties::getMaxHttpFormPostSize).asInt(DataSize::toBytes)
					.when((maxHttpFormPostSize) -> maxHttpFormPostSize != 0)
					.to((maxHttpFormPostSize) -> customizeMaxHttpFormPostSize(factory, maxHttpFormPostSize));
			propertyMapper.from(tomcatProperties::getAccesslog).when(ServerProperties.Tomcat.Accesslog::isEnabled)
					.to((enabled) -> customizeAccessLog(factory));
			propertyMapper.from(tomcatProperties::getUriEncoding).whenNonNull().to(factory::setUriEncoding);

			propertyMapper.from(tomcatProperties::getConnectionTimeout).whenNonNull()
					.to((connectionTimeout) -> customizeConnectionTimeout(factory, connectionTimeout));
			
			propertyMapper.from(tomcatProperties::getMaxConnections).when(this::isPositive)
					.to((maxConnections) -> customizeMaxConnections(factory, maxConnections));
					
			propertyMapper.from(tomcatProperties::getAcceptCount).when(this::isPositive)
					.to((acceptCount) -> customizeAcceptCount(factory, acceptCount));
					
			propertyMapper.from(tomcatProperties::getProcessorCache)
					.to((processorCache) -> customizeProcessorCache(factory, processorCache));
			propertyMapper.from(tomcatProperties::getRelaxedPathChars).as(this::joinCharacters).whenHasText()
					.to((relaxedChars) -> customizeRelaxedPathChars(factory, relaxedChars));
			propertyMapper.from(tomcatProperties::getRelaxedQueryChars).as(this::joinCharacters).whenHasText()
					.to((relaxedChars) -> customizeRelaxedQueryChars(factory, relaxedChars));
			customizeStaticResources(factory);
			customizeErrorReportValve(properties.getError(), factory);
		}
		private boolean isPositive(int value) {
		return value > 0;
	}

	private void customizeAcceptCount(ConfigurableTomcatWebServerFactory factory, int acceptCount) {
		factory.addConnectorCustomizers((connector) -> {
			ProtocolHandler handler = connector.getProtocolHandler();
			if (handler instanceof AbstractProtocol) {
				AbstractProtocol<?> protocol = (AbstractProtocol<?>) handler;
				protocol.setAcceptCount(acceptCount);
			}
		});
	}

	private void customizeProcessorCache(ConfigurableTomcatWebServerFactory factory, int processorCache) {
		factory.addConnectorCustomizers((connector) -> {
			ProtocolHandler handler = connector.getProtocolHandler();
			if (handler instanceof AbstractProtocol) {
				((AbstractProtocol<?>) handler).setProcessorCache(processorCache);
			}
		});
	}

	private void customizeMaxConnections(ConfigurableTomcatWebServerFactory factory, int maxConnections) {
		factory.addConnectorCustomizers((connector) -> {
			ProtocolHandler handler = connector.getProtocolHandler();
			if (handler instanceof AbstractProtocol) {
				AbstractProtocol<?> protocol = (AbstractProtocol<?>) handler;
				protocol.setMaxConnections(maxConnections);
			}
		});
	}

	private void customizeConnectionTimeout(ConfigurableTomcatWebServerFactory factory, Duration connectionTimeout) {
		factory.addConnectorCustomizers((connector) -> {
			ProtocolHandler handler = connector.getProtocolHandler();
			if (handler instanceof AbstractProtocol) {
				AbstractProtocol<?> protocol = (AbstractProtocol<?>) handler;
				protocol.setConnectionTimeout((int) connectionTimeout.toMillis());
			}
		});
	}
	
	@SuppressWarnings("rawtypes")
	private void customizeMaxThreads(ConfigurableTomcatWebServerFactory factory, int maxThreads) {
		factory.addConnectorCustomizers((connector) -> {
			ProtocolHandler handler = connector.getProtocolHandler();
			if (handler instanceof AbstractProtocol) {
				AbstractProtocol protocol = (AbstractProtocol) handler;
				protocol.setMaxThreads(maxThreads);
			}
		});
	}

	@SuppressWarnings("rawtypes")
	private void customizeMinThreads(ConfigurableTomcatWebServerFactory factory, int minSpareThreads) {
		factory.addConnectorCustomizers((connector) -> {
			ProtocolHandler handler = connector.getProtocolHandler();
			if (handler instanceof AbstractProtocol) {
				AbstractProtocol protocol = (AbstractProtocol) handler;
				protocol.setMinSpareThreads(minSpareThreads);
			}
		});
	}


	}

参数分析

Tomcat内部类maxConnections属性

提出关键代码:

org.springframework.boot.autoconfigure.web.embedded.TomcatWebServerFactoryCustomizer#customizeMaxConnections

		/**
		 * Maximum number of connections that the server accepts and processes at any
		 * given time. Once the limit has been reached, the operating system may still
		 * accept connections based on the "acceptCount" property.
		 * 服务器在任何给定时间接受和处理的最大连接数。一旦达到限制,操作系统仍可能接受基于“acceptCount”属性的连接。
		 */
		private int maxConnections = 8192;
		
		private void customizeMaxConnections(ConfigurableTomcatWebServerFactory factory, int maxConnections) {
		factory.addConnectorCustomizers((connector) -> {
			ProtocolHandler handler = connector.getProtocolHandler();
			if (handler instanceof AbstractProtocol) {
				AbstractProtocol<?> protocol = (AbstractProtocol<?>) handler;
				//org.apache.coyote.AbstractProtocol#setMaxConnections
				protocol.setMaxConnections(maxConnections);
			}
		});
	}

org.apache.coyote.AbstractProtocol#setMaxConnections:

最终是被AbstractEndpoint#sexMaxConnections设置了

org.apache.coyote.AbstractProtocol#setMaxConnections
抽象类AbstractEndpoint的具体方法:

    private int maxConnections = 8*1024;
    
    public void setMaxConnections(int maxCon) {
        this.maxConnections = maxCon;
        //org.apache.tomcat.util.threads.LimitLatch
        LimitLatch latch = this.connectionLimitLatch;
        if (latch != null) {
            // Update the latch that enforces this
            if (maxCon == -1) {
                releaseConnectionLatch();
            } else {
                latch.setLimit(maxCon);
            }
        } else if (maxCon > 0) {
            initializeConnectionLatch();
        }
    }
    private void releaseConnectionLatch() {
        LimitLatch latch = connectionLimitLatch;
        if (latch!=null) latch.releaseAll();
        connectionLimitLatch = null;
    }
    
     protected LimitLatch initializeConnectionLatch() {
        if (maxConnections==-1) return null;
        if (connectionLimitLatch==null) {
            connectionLimitLatch = new LimitLatch(getMaxConnections());
        }
        return connectionLimitLatch;
    }

这里离不开org.apache.tomcat.util.threads.LimitLatch,先看下这个类的作用:
在这里插入图片描述
经过上面初始化LimitLatch的构造器方法可知,其参数是maxConnections,也就是LimitLatch的limit属性:

	  private final Sync sync;
	  private final AtomicLong count;
	  private volatile long limit;
    /**
     * Instantiates a LimitLatch object with an initial limit.
     * @param limit - maximum number of concurrent acquisitions of this latch
     */
    public LimitLatch(long limit) {
        this.limit = limit;
        this.count = new AtomicLong(0);
        this.sync = new Sync();
    }

重点关注下谁使用了LimitLatch的limit,可以看到是Acceptor用来判断连接是否达到了最大值。
在这里插入图片描述
LimitLatch内部依赖了Sync内部类,继承了AbstractQueuedSynchronizer并覆盖了其tryAcquireShared方法:

  //AQS的acquireSharedInterruptibly方法
  public final void acquireSharedInterruptibly(int arg)
            throws InterruptedException {
        if (Thread.interrupted())
            throw new InterruptedException();
        /**
        * LimitLatch#Sync的tryAcquireShared方法由于count超过了maxConnections而返回-1,
        * 于是执行doAcquireSharedInterruptibly,将当前线程封装为一个Shared(nextWaiter状态)节点插入到AQS队列尾部。
        * 如果队列除了头部哨兵之外只有当前线程一个节点,则重新尝试递增LimitLatch的count判断是否大于maxConnections,
        * 如果没有大于,则应该要唤醒AQS线程去加入继续Acceptor的流程:封装为events放入Poller事件队列
        * 如果仍然是大于,则将当前Thread插入AQS队列挂起。
        * 
        */
        if (tryAcquireShared(arg) < 0)
            doAcquireSharedInterruptibly(arg);
  }
   /**
     * Acquires in shared interruptible mode.
     * @param arg the acquire argument
     */
    private void doAcquireSharedInterruptibly(int arg)
        throws InterruptedException {
        final Node node = addWaiter(Node.SHARED);
        boolean failed = true;
        try {
            for (;;) {
                final Node p = node.predecessor();
                if (p == head) {
                    int r = tryAcquireShared(arg);
                    if (r >= 0) {
                        setHeadAndPropagate(node, r);
                        p.next = null; // help GC
                        failed = false;
                        return;
                    }
                }
                if (shouldParkAfterFailedAcquire(p, node) &&
                    parkAndCheckInterrupt())
                    throw new InterruptedException();
            }
        } finally {
            if (failed)
                cancelAcquire(node);
        }
    }
     /**
     * Convenience method to park and then check if interrupted
     *
     * @return {@code true} if interrupted
     */
    private final boolean parkAndCheckInterrupt() {
        LockSupport.park(this);
        return Thread.interrupted();
    }
public class LimitLatch {

    private static final Log log = LogFactory.getLog(LimitLatch.class);

    private class Sync extends AbstractQueuedSynchronizer {
        private static final long serialVersionUID = 1L;

        public Sync() {
        }
		
		/**
		*  count初始值0,随着Acceptor线程接收的连接越来越多,count会count.incrementAndGet()增长,
		*  直到count大于limit(maxConnections)时,tryAcquireShared返回-1,同时count计数器也会递减。
		*/
        @Override
        protected int tryAcquireShared(int ignored) {
            long newCount = count.incrementAndGet();
            if (!released && newCount > limit) {
                // Limit exceeded
                count.decrementAndGet();
                return -1;
            } else {
                return 1;
            }
        }

        @Override
        protected boolean tryReleaseShared(int arg) {
            count.decrementAndGet();
            return true;
        }
    }

    private final Sync sync;
    private final AtomicLong count;
    private volatile long limit;
    private volatile boolean released = false;

    /**
     * Instantiates a LimitLatch object with an initial limit.
     * @param limit - maximum number of concurrent acquisitions of this latch
     */
    public LimitLatch(long limit) {
        this.limit = limit;
        this.count = new AtomicLong(0);
        this.sync = new Sync();
    }
  }

总结:基于以上分析,可以确定一点,Acceptor线程一旦发现ServerSocketChannel返回了SocketChannel,就会调用org.apache.tomcat.util.net.NioEndpoint#setSocketOptions去注册SocketChannel到PollerEvent并订阅SelectionKey.OP_READ事件:

         /** 位置:**org.apache.tomcat.util.net.NioEndpoint.Poller#register**
         *   
         * 
         * Registers a newly created socket with the poller.
         *
         * @param socket    The newly created socket
         * @param socketWrapper The socket wrapper
         */
        public void register(final NioChannel socket, final NioSocketWrapper socketWrapper) {
            socketWrapper.interestOps(SelectionKey.OP_READ);//this is what OP_REGISTER turns into.
            PollerEvent event = null;
            if (eventCache != null) {
                event = eventCache.pop();
            }
            if (event == null) {
                event = new PollerEvent(socket, OP_REGISTER);
            } else {
                event.reset(socket, OP_REGISTER);
            }
            addEvent(event);
        }
        
        /** 这是一个同步队列,放进去就立马要被Poller线程的Run方法取出来,丢到Worker线程池:
        * Executor executor = getExecutor();
            if (dispatch && executor != null) {
                executor.execute(sc);
            } else {
                sc.run();
            }
        */
        
        private final SynchronizedQueue<PollerEvent> events = new SynchronizedQueue<>();

        private void addEvent(PollerEvent event) {
            events.offer(event);
            if (wakeupCounter.incrementAndGet() == 0) {
                selector.wakeup();
            }
        }

        
 /**  位置: org.apache.tomcat.util.net.NioEndpoint.PollerEvent
     * PollerEvent, cacheable object for poller events to avoid GC
     */
    public static class PollerEvent {

        private NioChannel socket;
        private int interestOps;

        public PollerEvent(NioChannel ch, int intOps) {
            reset(ch, intOps);
        }

        public void reset(NioChannel ch, int intOps) {
            socket = ch;
            interestOps = intOps;
        }

        public NioChannel getSocket() {
            return socket;
        }

        public int getInterestOps() {
            return interestOps;
        }

        public void reset() {
            reset(null, 0);
        }

        @Override
        public String toString() {
            return "Poller event: socket [" + socket + "], socketWrapper [" + socket.getSocketWrapper() +
                    "], interestOps [" + interestOps + "]";
        }
    }

Worker线程业务处理完成之后SocketChannel会被释放

Tomcat内部类的acceptCount

org.apache.tomcat.util.net.NioEndpoint在初始化时,initServerSocket时候会以参数传入


    /**
     * Initialize the endpoint.
     */
    @Override
    public void bind() throws Exception {
        initServerSocket();

        setStopLatch(new CountDownLatch(1));

        // Initialize SSL if needed
        initialiseSsl();

        selectorPool.open(getName());
    }

    // Separated out to make it easier for folks that extend NioEndpoint to
    // implement custom [server]sockets
    protected void initServerSocket() throws Exception {
        if (!getUseInheritedChannel()) {
            serverSock = ServerSocketChannel.open();
            socketProperties.setProperties(serverSock.socket());
            InetSocketAddress addr = new InetSocketAddress(getAddress(), getPortWithOffset());
            
            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
    }

acceptCount根据源码说明是一个应对请求积压的值,但最终这个值是传入了一个jni的native方法:


    /**
     * 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;

所以,这里的积压应该是在TCP的读缓冲区里积压的请求数,看了一些文章的说法是:

acceptCount的队列中缓存的是建立了TCP连接等待被应用层ServerSocketChannel#accept方法返回的请求。accept队列也满了之后便会拒绝新的请求,并且没被及时处理的队列中的TCP连接会发出超时timeout响应。

在这里插入图片描述

Tomcat有几个Acceptor线程

把断点打在构造函数中,会发现在启动阶段只有一次调用:

   public Acceptor(AbstractEndpoint<?,U> endpoint) {
        this.endpoint = endpoint;
    }

通过debug可以看到明显的执行时序:

  1. org.springframework.boot.web.servlet.context.WebServerStartStopLifecycle#start
	@Override
	public void start() {
		this.webServer.start();
		this.running = true;
		this.applicationContext
				.publishEvent(new ServletWebServerInitializedEvent(this.webServer, this.applicationContext));
	}
  1. org.springframework.boot.web.embedded.tomcat.TomcatWebServer#addPreviouslyRemovedConnectors
public void start() throws WebServerException {
	synchronized (this.monitor) {
			if (this.started) {
				return;
			}
			try {
				addPreviouslyRemovedConnectors();
				.....
			}
			catch (ConnectorStartFailedException ex) {
				stopSilently();
				throw ex;
			}
			catch (Exception ex) {
				PortInUseException.throwIfPortBindingException(ex, () -> this.tomcat.getConnector().getPort());
				throw new WebServerException("Unable to start embedded Tomcat server", ex);
			}
			finally {
				Context context = findContext();
				ContextBindings.unbindClassLoader(context, context.getNamingToken(), getClass().getClassLoader());
			}
		}
}
	private void addPreviouslyRemovedConnectors() {
		Service[] services = this.tomcat.getServer().findServices();
		for (Service service : services) {
			Connector[] connectors = this.serviceConnectors.get(service);
			if (connectors != null) {
				for (Connector connector : connectors) {
					service.addConnector(connector);//添加Connector并启动
					if (!this.autoStart) {
						stopProtocolHandler(connector);
					}
				}
				this.serviceConnectors.remove(service);
			}
		}
	}

这里明显看到只有一个Service(StandardService),而这个Service也只包含了一个Connector(即Tomcat默认的Http Connector,默认8080),其实Tomcat的Connector类型还有几中:

  • AJP Connector:端口默认8009
  • APR Connector: 高性能扩展使用
  • Https Connector
    在这里插入图片描述

在这里插入图片描述
为什么只有一个,这里要看下添加的地方,这个地方的代码挺有意思的,有空一定要好好研究下:

  • org.springframework.boot.web.servlet.context.ServletWebServerApplicationContext#onRefresh
@Override
	protected void onRefresh() {
		super.onRefresh();
		try {
			createWebServer();
		}
		catch (Throwable ex) {
			throw new ApplicationContextException("Unable to start web server", ex);
		}
	}
  • org.springframework.boot.web.servlet.context.ServletWebServerApplicationContext#createWebServer
private void createWebServer() {
		WebServer webServer = this.webServer;
		ServletContext servletContext = getServletContext();
		if (webServer == null && servletContext == null) {
			ServletWebServerFactory factory = getWebServerFactory();
			this.webServer = factory.getWebServer(getSelfInitializer());
			getBeanFactory().registerSingleton("webServerGracefulShutdown",
					new WebServerGracefulShutdownLifecycle(this.webServer));
			getBeanFactory().registerSingleton("webServerStartStop",
					new WebServerStartStopLifecycle(this, this.webServer));
		}
		else if (servletContext != null) {
			try {
				getSelfInitializer().onStartup(servletContext);
			}
			catch (ServletException ex) {
				throw new ApplicationContextException("Cannot initialize servlet context", ex);
			}
		}
		initPropertySources();
	}
  • org.springframework.boot.web.embedded.tomcat.TomcatServletWebServerFactory#getWebServer
  public Service getService() {
        return getServer().findServices()[0];
    }
       /**
     * Get the server object. You can add listeners and few more
     * customizations. JNDI is disabled by default.
     * @return The Server
     */
    public Server getServer() {

        if (server != null) {
            return server;
        }

        System.setProperty("catalina.useNaming", "false");

        server = new StandardServer();

        initBaseDir();

        // Set configuration source
        ConfigFileLoader.setSource(new CatalinaBaseConfigurationSource(new File(basedir), null));

        server.setPort( -1 );
		//这里也只创建了一个Service
        Service service = new StandardService();
        service.setName("Tomcat");
        server.addService(service);
        return server;
    }
    
    @Override
	public WebServer getWebServer(ServletContextInitializer... initializers) {
		if (this.disableMBeanRegistry) {
			Registry.disableRegistry();
		}
		Tomcat tomcat = new Tomcat();
		File baseDir = (this.baseDirectory != null) ? this.baseDirectory : createTempDir("tomcat");
		tomcat.setBaseDir(baseDir.getAbsolutePath());
		//这里的确就创建了一个Connector
		Connector connector = new Connector(this.protocol);
		connector.setThrowOnFailure(true);
		tomcat.getService().addConnector(connector);
		customizeConnector(connector);
		tomcat.setConnector(connector);
		tomcat.getHost().setAutoDeploy(false);
		configureEngine(tomcat.getEngine());
		for (Connector additionalConnector : this.additionalTomcatConnectors) {
			tomcat.getService().addConnector(additionalConnector);
		}
		prepareContext(tomcat.getHost(), initializers);
		return getTomcatWebServer(tomcat);
	}
  1. org.apache.catalina.core.StandardService#addConnector
/**
     * Add a new Connector to the set of defined Connectors, and associate it
     * with this Service's Container.
     *
     * @param connector The Connector to be added
     */
    @Override
    public void addConnector(Connector connector) {

        synchronized (connectorsLock) {
            connector.setService(this);
            Connector results[] = new Connector[connectors.length + 1];
            System.arraycopy(connectors, 0, results, 0, connectors.length);
            results[connectors.length] = connector;
            connectors = results;
        }

        try {
            if (getState().isAvailable()) {
                connector.start();//启动connector,Connector继承了LifecycleMBeanBase
            }
        } catch (LifecycleException e) {
            throw new IllegalArgumentException(
                    sm.getString("standardService.connector.startFailed", connector), e);
        }

        // Report this property change to interested listeners
        support.firePropertyChange("connector", null, connector);
    }
  1. org.apache.catalina.util.LifecycleBase#start
 /**
     * {@inheritDoc}
     */
    @Override
    public final synchronized void start() throws LifecycleException {

        if (LifecycleState.STARTING_PREP.equals(state) || LifecycleState.STARTING.equals(state) ||
                LifecycleState.STARTED.equals(state)) {

            if (log.isDebugEnabled()) {
                Exception e = new LifecycleException();
                log.debug(sm.getString("lifecycleBase.alreadyStarted", toString()), e);
            } else if (log.isInfoEnabled()) {
                log.info(sm.getString("lifecycleBase.alreadyStarted", toString()));
            }

            return;
        }

        if (state.equals(LifecycleState.NEW)) {
            init();
        } else if (state.equals(LifecycleState.FAILED)) {
            stop();
        } else if (!state.equals(LifecycleState.INITIALIZED) &&
                !state.equals(LifecycleState.STOPPED)) {
            invalidTransition(Lifecycle.BEFORE_START_EVENT);
        }

        try {
            setStateInternal(LifecycleState.STARTING_PREP, null, false);
            startInternal();//启动Connector内部流程
            if (state.equals(LifecycleState.FAILED)) {
                // This is a 'controlled' failure. The component put itself into the
                // FAILED state so call stop() to complete the clean-up.
                stop();
            } else if (!state.equals(LifecycleState.STARTING)) {
                // Shouldn't be necessary but acts as a check that sub-classes are
                // doing what they are supposed to.
                invalidTransition(Lifecycle.AFTER_START_EVENT);
            } else {
                setStateInternal(LifecycleState.STARTED, null, false);
            }
        } catch (Throwable t) {
            // This is an 'uncontrolled' failure so put the component into the
            // FAILED state and throw an exception.
            handleSubClassException(t, "lifecycleBase.startFail", toString());
        }
    }
  1. org.apache.catalina.connector.Connector#startInternal
/**
     * Begin processing requests via this Connector.
     *
     * @exception LifecycleException if a fatal startup error occurs
     */
    @Override
    protected void startInternal() throws LifecycleException {

        // Validate settings before starting
        if (getPortWithOffset() < 0) {
            throw new LifecycleException(sm.getString(
                    "coyoteConnector.invalidPort", Integer.valueOf(getPortWithOffset())));
        }

        setState(LifecycleState.STARTING);

        try {
            protocolHandler.start();
        } catch (Exception e) {
            throw new LifecycleException(
                    sm.getString("coyoteConnector.protocolHandlerStartFailed"), e);
        }
    }
  1. org.apache.coyote.AbstractProtocol#start
 @Override
    public void start() throws Exception {
        if (getLog().isInfoEnabled()) {
            getLog().info(sm.getString("abstractProtocolHandler.start", getName()));
            logPortOffset();
        }

        endpoint.start();
        monitorFuture = getUtilityExecutor().scheduleWithFixedDelay(
                new Runnable() {
                    @Override
                    public void run() {
                        if (!isPaused()) {
                            startAsyncTimeout();
                        }
                    }
                }, 0, 60, TimeUnit.SECONDS);
    }
  1. 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. org.apache.tomcat.util.net.NioEndpoint#startInternal
 /**
     * Start the NIO endpoint, creating acceptor, poller threads.
     */
    @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());
            }

            // Create worker collection
            if (getExecutor() == null) {
                createExecutor();
            }

            initializeConnectionLatch();

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

            startAcceptorThread();
        }
    }
  1. org.apache.tomcat.util.net.AbstractEndpoint#startAcceptorThread
    protected void startAcceptorThread() {
        //到这一步创建Acceptor线程直接启动
        acceptor = new Acceptor<>(this);
        String threadName = getName() + "-Acceptor";
        acceptor.setThreadName(threadName);
        Thread t = new Thread(acceptor, threadName);
        t.setPriority(getAcceptorThreadPriority());
        t.setDaemon(getDaemon());
        t.start();
    }

Tomcat的工作线程池

这里其实没什么好说的,主要就是这个TaskQueue是继承了LinkedBlockingQueue是无界队列。
在这里插入图片描述
在这里插入图片描述
在这里插入图片描述

本文来自互联网用户投稿,该文观点仅代表作者本人,不代表本站立场。本站仅提供信息存储空间服务,不拥有所有权,不承担相关法律责任。如若转载,请注明出处:/a/940457.html

如若内容造成侵权/违法违规/事实不符,请联系我们进行投诉反馈qq邮箱809451989@qq.com,一经查实,立即删除!

相关文章

网络安全核心目标CIA

网络安全的核心目标是为关键资产提供机密性(Confidentiality)、可用性(Availablity)、完整性(Integrity)。作为安全基础架构中的主要的安全目标和宗旨&#xff0c;机密性、可用性、完整性频频出现&#xff0c;被简称为CIA&#xff0c;也被成为你AIC&#xff0c;只是顺序不同而已…

HIPT论文阅读

题目《Scaling Vision Transformers to Gigapixel Images via Hierarchical Self-Supervised Learning》 论文地址&#xff1a;[2206.02647] Scaling Vision Transformers to Gigapixel Images via Hierarchical Self-Supervised Learning 项目地址&#xff1a;mahmoodlab/HI…

智能挂号系统设计典范:SSM 结合 Vue 在医院的应用实现

摘要 随着信息技术在管理上越来越深入而广泛的应用&#xff0c;管理信息系统的实施在技术上已逐步成熟。本文介绍了医院预约挂号系统的开发全过程。通过分析医院预约挂号系统管理的不足&#xff0c;创建了一个计算机管理医院预约挂号系统的方案。文章介绍了医院预约挂号系统的系…

Windows11 家庭版安装配置 Docker

1. 安装WSL WSL 是什么&#xff1a; WSL 是一个在 Windows 上运行 Linux 环境的轻量级工具&#xff0c;它可以让用户在 Windows 系统中运行 Linux 工具和应用程序。Docker 为什么需要 WSL&#xff1a; Docker 依赖 Linux 内核功能&#xff0c;WSL 2 提供了一个高性能、轻量级的…

【hackmyvm】Diophante 靶场

1. 基本信息^toc 这里写目录标题 1. 基本信息^toc2. 信息收集2.1. 端口扫描2.2. 目录扫描2.3. knock 3. WordPress利用3.1. wpscan扫描3.2. smtp上传后门 4. 提权4.1. 提权leonard用户4.2. LD劫持提权root 靶机链接 https://hackmyvm.eu/machines/machine.php?vmDiophante 作者…

OB删除1.5亿数据耗费2小时

目录 回顾&#xff1a;mysql是怎么删除数据的&#xff1f; 删除方案 代码实现 执行结果 结论 本篇是实际操作 批量处理数据以及线程池线程数设置 记录学习 背景&#xff1a;有一张用户标签表&#xff0c;存储数据量达4个亿&#xff0c;使用OceanBase存储&#xff0c;由于…

Qt:QMetaObject::connectSlotsByName实现信号槽自动关联

简介 在Qt中&#xff0c;QMetaObject::connectSlotsByName 是一个便利的方法&#xff0c;它可以根据对象的对象名&#xff08;objectName&#xff09;自动将信号和槽连接起来。但是&#xff0c;要使用这个方法&#xff0c;必须确保&#xff1a; 1 控件&#xff08;如按钮&…

记录仪方案_记录仪安卓主板定制_音视频记录仪PCBA定制开发

记录仪主板采用了强大的联发科MTK8768处理器&#xff0c;拥有出色的性能表现。它搭载了四个主频为2.0GHz的Cortex-A53核心与四个主频为1.5GHz的Cortex-A53核心&#xff0c;确保了高效的处理速度。此外&#xff0c;主板配备了4GB的RAM(可选8GB)&#xff0c;并且内置64GB的ROM(可…

Ubuntu 20.04 卸载和安装 MySQL8.0

卸载 首先&#xff0c;检查一下系统安装的软件包有哪些&#xff0c;使用dpkg -l | grep mysql命令&#xff1a; 为了将MySQL卸载干净&#xff0c;这些文件都需要被删除。 在Ubuntu20.04系统下&#xff0c;卸载干净MySQL8.0以确保下一次安装不会出错&#xff0c;可以按照以下…

RCNN系列是如何逐步改善的

1、R-CNN的缺点&#xff1a; 1&#xff09;计算效率低下&#xff1a;RCNN需要为每一个候选框都提取特征&#xff0c;会导致大量重复的工作&#xff0c;因为候选框是原始图片的一部分&#xff0c;肯定是存在交集的。2&#xff09;需要大量的磁盘空间&#xff1a;在训练阶段&…

数据结构day5:单向循环链表 代码作业

一、loopLink.h #ifndef __LOOPLINK_H__ #define __LOOPLINK_H__#include <stdio.h> #include <stdlib.h>typedef int DataType;typedef struct node {union{int len;DataType data;};struct node* next; }loopLink, *loopLinkPtr;//创建 loopLinkPtr create();//…

后摩尔定律时代,什么将推动计算机性能优化的发展?

在摩尔定律时代&#xff0c;每两年芯片上的晶体管数量就会翻一番&#xff0c;这一看似不可避免的趋势被称为摩尔定律&#xff0c;它极大地促进了计算机性能的提高。然而&#xff0c;硅基晶体管不可能一直小下去&#xff0c;半导体晶体管的微型化推动了计算机性能的提升&#xf…

LEAST-TO-MOST PROMPTING ENABLES COMPLEX REASONING IN LARGE LANGUAGE MODELS---正文

题目 最少到最多的提示使大型语言模型能够进行复杂的推理 论文地址&#xff1a;https://arxiv.org/abs/2205.10625 摘要 思路链提示在各种自然语言推理任务中表现出色。然而&#xff0c;它在需要解决比提示中显示的示例更难的问题的任务上表现不佳。为了克服这种由易到难的概括…

0101多级nginx代理websocket配置-nginx-web服务器

1. 前言 项目一些信息需要通过站内信主动推动给用户&#xff0c;使用websocket。web服务器选用nginx&#xff0c;但是域名是以前通过阿里云申请的&#xff0c;解析ip也是阿里云的服务器&#xff0c;甲方不希望更换域名。新的系统需要部署在内网服务器&#xff0c;简单拓扑图如…

Mysql8版本的下载安装配置,无痛使用!!!!

mysql8.x版本和msyql5.x版本zip安装的方式大同小异&#xff0c;但是在mysql8.0版本不用手动创建data数据目录&#xff0c;初始化的时候会自动安装的。而且mysql8.0版本性能官方表示比mysql 5.7的快两倍&#xff01; 可以查看文章看5.7版本的安装 MySql5.7安装、配置最新版_my…

《商业模式2.0图鉴》读书笔记(如何构建创新驱动的商业模式:打破定律与重塑价值)

文章目录 引言一、构建创新商业模式的核心原则二、创新商业模式的构建维度三、商业模式设计的实践工具与方法四、从现状到未来&#xff1a;商业模式的演进路径结论附录标题图 引言 商业模式是企业连接资源与客户的桥梁&#xff0c;是价值创造与捕获的核心框架。随着市场需求和…

【数据结构】数据结构整体大纲

数据结构用来干什么的&#xff1f;很简单&#xff0c;存数据用的。 &#xff08;这篇文章仅介绍数据结构的大纲&#xff0c;详细讲解放在后面的每一个章节中&#xff0c;逐个击破&#xff09; 那为什么不直接使用数组、集合来存储呢 ——> 如果有成千上亿条数据呢&#xff…

Flutter组件————FloatingActionButton

FloatingActionButton 是Flutter中的一个组件&#xff0c;通常用于显示一个圆形的按钮&#xff0c;它悬浮在内容之上&#xff0c;旨在吸引用户的注意力&#xff0c;并代表屏幕上的主要动作。这种按钮是Material Design的一部分&#xff0c;通常放置在页面的右下角&#xff0c;但…

python rabbitmq实现简单/持久/广播/组播/topic/rpc消息异步发送可配置Django

windows首先安装rabbitmq 点击参考安装 1、环境介绍 Python 3.10.16 其他通过pip安装的版本(Django、pika、celery这几个必须要有最好版本一致) amqp 5.3.1 asgiref 3.8.1 async-timeout 5.0.1 billiard 4.2.1 celery 5.4.0 …

【Verilog】期末复习

数字逻辑电路分为哪两类&#xff1f;它们各自的特点是什么&#xff1f; 组合逻辑电路&#xff1a;任意时刻的输出仅仅取决于该时刻的输入&#xff0c;而与电路原来的状态无关 没有记忆功能&#xff0c;只有从输入到输出的通路&#xff0c;没有从输出到输入的回路 时序逻辑电路&…