/* * Licensed to the Apache Software Foundation (ASF) under one or more * contributor license agreements. See the NOTICE file distributed with * this work for additional information regarding copyright ownership. * The ASF licenses this file to You under the Apache License, Version 2.0 * (the "License"); you may not use this file except in compliance with * the License. You may obtain a copy of the License at * * http://www.apache.org/licenses/LICENSE-2.0 * * Unless required by applicable law or agreed to in writing, software * distributed under the License is distributed on an "AS IS" BASIS, * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. * See the License for the specific language governing permissions and * limitations under the License. */ package org.apache.catalina.core; import java.util.concurrent.RejectedExecutionException; import java.util.concurrent.TimeUnit; import org.apache.catalina.Executor; import org.apache.catalina.LifecycleException; import org.apache.catalina.LifecycleState; import org.apache.catalina.util.LifecycleMBeanBase; import org.apache.tomcat.util.threads.ResizableExecutor; import org.apache.tomcat.util.threads.TaskQueue; import org.apache.tomcat.util.threads.TaskThreadFactory; import org.apache.tomcat.util.threads.ThreadPoolExecutor; public class StandardThreadExecutor extends LifecycleMBeanBase implements Executor, ResizableExecutor { // ---------------------------------------------- Properties /** * Default thread priority */ protected int threadPriority = Thread.NORM_PRIORITY; /** * Run threads in daemon or non-daemon state */ protected boolean daemon = true; /** * Default name prefix for the thread name */ protected String namePrefix = "tomcat-exec-"; /** * max number of threads */ protected int maxThreads = 200; /** * min number of threads */ protected int minSpareThreads = 25; /** * idle time in milliseconds */ protected int maxIdleTime = 60000; /** * The executor we use for this component */ protected ThreadPoolExecutor executor = null; /** * the name of this thread pool */ protected String name; /** * prestart threads? */ protected boolean prestartminSpareThreads = false; /** * The maximum number of elements that can queue up before we reject them */ protected int maxQueueSize = Integer.MAX_VALUE; /** * After a context is stopped, threads in the pool are renewed. To avoid * renewing all threads at the same time, this delay is observed between 2 * threads being renewed. */ protected long threadRenewalDelay = org.apache.tomcat.util.threads.Constants.DEFAULT_THREAD_RENEWAL_DELAY; private TaskQueue taskqueue = null; // ---------------------------------------------- Constructors public StandardThreadExecutor() { //empty constructor for the digester } // ---------------------------------------------- Public Methods @Override protected void initInternal() throws LifecycleException { super.initInternal(); } /** * Start the component and implement the requirements * of {@link org.apache.catalina.util.LifecycleBase#startInternal()}. * * @exception LifecycleException if this component detects a fatal error * that prevents this component from being used */ @Override protected void startInternal() throws LifecycleException { taskqueue = new TaskQueue(maxQueueSize); TaskThreadFactory tf = new TaskThreadFactory(namePrefix,daemon,getThreadPriority()); executor = new ThreadPoolExecutor(getMinSpareThreads(), getMaxThreads(), maxIdleTime, TimeUnit.MILLISECONDS,taskqueue, tf); executor.setThreadRenewalDelay(threadRenewalDelay); if (prestartminSpareThreads) { executor.prestartAllCoreThreads(); } taskqueue.setParent(executor); setState(LifecycleState.STARTING); } /** * Stop the component and implement the requirements * of {@link org.apache.catalina.util.LifecycleBase#stopInternal()}. * * @exception LifecycleException if this component detects a fatal error * that needs to be reported */ @Override protected void stopInternal() throws LifecycleException { setState(LifecycleState.STOPPING); if ( executor != null ) executor.shutdownNow(); executor = null; taskqueue = null; } @Override protected void destroyInternal() throws LifecycleException { super.destroyInternal(); } @Override public void execute(Runnable command, long timeout, TimeUnit unit) { if ( executor != null ) { executor.execute(command,timeout,unit); } else { throw new IllegalStateException("StandardThreadExecutor not started."); } } @Override public void execute(Runnable command) { if ( executor != null ) { try { executor.execute(command); } catch (RejectedExecutionException rx) { //there could have been contention around the queue if ( !( (TaskQueue) executor.getQueue()).force(command) ) throw new RejectedExecutionException("Work queue full."); } } else throw new IllegalStateException("StandardThreadPool not started."); } public void contextStopping() { if (executor != null) { executor.contextStopping(); } } public int getThreadPriority() { return threadPriority; } public boolean isDaemon() { return daemon; } public String getNamePrefix() { return namePrefix; } public int getMaxIdleTime() { return maxIdleTime; } @Override public int getMaxThreads() { return maxThreads; } public int getMinSpareThreads() { return minSpareThreads; } @Override public String getName() { return name; } public boolean isPrestartminSpareThreads() { return prestartminSpareThreads; } public void setThreadPriority(int threadPriority) { this.threadPriority = threadPriority; } public void setDaemon(boolean daemon) { this.daemon = daemon; } public void setNamePrefix(String namePrefix) { this.namePrefix = namePrefix; } public void setMaxIdleTime(int maxIdleTime) { this.maxIdleTime = maxIdleTime; if (executor != null) { executor.setKeepAliveTime(maxIdleTime, TimeUnit.MILLISECONDS); } } public void setMaxThreads(int maxThreads) { this.maxThreads = maxThreads; if (executor != null) { executor.setMaximumPoolSize(maxThreads); } } public void setMinSpareThreads(int minSpareThreads) { this.minSpareThreads = minSpareThreads; if (executor != null) { executor.setCorePoolSize(minSpareThreads); } } public void setPrestartminSpareThreads(boolean prestartminSpareThreads) { this.prestartminSpareThreads = prestartminSpareThreads; } public void setName(String name) { this.name = name; } public void setMaxQueueSize(int size) { this.maxQueueSize = size; } public int getMaxQueueSize() { return maxQueueSize; } public long getThreadRenewalDelay() { return threadRenewalDelay; } public void setThreadRenewalDelay(long threadRenewalDelay) { this.threadRenewalDelay = threadRenewalDelay; if (executor != null) { executor.setThreadRenewalDelay(threadRenewalDelay); } } // Statistics from the thread pool @Override public int getActiveCount() { return (executor != null) ? executor.getActiveCount() : 0; } public long getCompletedTaskCount() { return (executor != null) ? executor.getCompletedTaskCount() : 0; } public int getCorePoolSize() { return (executor != null) ? executor.getCorePoolSize() : 0; } public int getLargestPoolSize() { return (executor != null) ? executor.getLargestPoolSize() : 0; } @Override public int getPoolSize() { return (executor != null) ? executor.getPoolSize() : 0; } public int getQueueSize() { return (executor != null) ? executor.getQueue().size() : -1; } @Override public boolean resizePool(int corePoolSize, int maximumPoolSize) { if (executor == null) return false; executor.setCorePoolSize(corePoolSize); executor.setMaximumPoolSize(maximumPoolSize); return true; } @Override public boolean resizeQueue(int capacity) { return false; } @Override protected String getDomainInternal() { // No way to navigate to Engine. Needs to have domain set. return null; } @Override protected String getObjectNameKeyProperties() { StringBuilder name = new StringBuilder("type=Executor,name="); name.append(getName()); return name.toString(); } }