You are viewing a plain text version of this content. The canonical link for it is here.
Posted to dev@tomcat.apache.org by re...@apache.org on 2018/11/08 10:17:44 UTC
svn commit: r1846116 - in /tomcat/trunk: java/org/apache/catalina/
java/org/apache/catalina/core/ java/org/apache/tomcat/util/threads/
test/org/apache/catalina/mbeans/ webapps/docs/ webapps/docs/config/
Author: remm
Date: Thu Nov 8 10:17:43 2018
New Revision: 1846116
URL: http://svn.apache.org/viewvc?rev=1846116&view=rev
Log:
Add a scheduled executor service to the Service, which can be used to process utility tasks including periodic ones.
Add a simple wrapper to prevent random lifecycle and configuration operations.
Add a bean for it.
Added:
tomcat/trunk/java/org/apache/tomcat/util/threads/ScheduledThreadPoolExecutor.java (with props)
Modified:
tomcat/trunk/java/org/apache/catalina/Service.java
tomcat/trunk/java/org/apache/catalina/core/StandardService.java
tomcat/trunk/test/org/apache/catalina/mbeans/TestRegistration.java
tomcat/trunk/webapps/docs/changelog.xml
tomcat/trunk/webapps/docs/config/service.xml
Modified: tomcat/trunk/java/org/apache/catalina/Service.java
URL: http://svn.apache.org/viewvc/tomcat/trunk/java/org/apache/catalina/Service.java?rev=1846116&r1=1846115&r2=1846116&view=diff
==============================================================================
--- tomcat/trunk/java/org/apache/catalina/Service.java (original)
+++ tomcat/trunk/java/org/apache/catalina/Service.java Thu Nov 8 10:17:43 2018
@@ -18,6 +18,8 @@
package org.apache.catalina;
+import java.util.concurrent.ScheduledExecutorService;
+
import org.apache.catalina.connector.Connector;
import org.apache.catalina.mapper.Mapper;
@@ -96,6 +98,20 @@ public interface Service extends Lifecyc
public String getDomain();
+ /**
+ * Get the utility thread count.
+ * @return the thread count
+ */
+ public int getUtilityThreads();
+
+
+ /**
+ * Set the utility thread count.
+ * @param utilityThreads the new thread count
+ */
+ public void setUtilityThreads(int utilityThreads);
+
+
// --------------------------------------------------------- Public Methods
/**
@@ -151,4 +167,10 @@ public interface Service extends Lifecyc
* @return the mapper associated with this Service.
*/
Mapper getMapper();
+
+ /**
+ * @return the utility executor managed by the Service.
+ */
+ ScheduledExecutorService getUtilityExecutor();
+
}
Modified: tomcat/trunk/java/org/apache/catalina/core/StandardService.java
URL: http://svn.apache.org/viewvc/tomcat/trunk/java/org/apache/catalina/core/StandardService.java?rev=1846116&r1=1846115&r2=1846116&view=diff
==============================================================================
--- tomcat/trunk/java/org/apache/catalina/core/StandardService.java (original)
+++ tomcat/trunk/java/org/apache/catalina/core/StandardService.java Thu Nov 8 10:17:43 2018
@@ -20,6 +20,11 @@ package org.apache.catalina.core;
import java.beans.PropertyChangeListener;
import java.beans.PropertyChangeSupport;
import java.util.ArrayList;
+import java.util.concurrent.ScheduledExecutorService;
+import java.util.concurrent.ScheduledThreadPoolExecutor;
+import java.util.concurrent.ThreadFactory;
+import java.util.concurrent.TimeUnit;
+import java.util.concurrent.atomic.AtomicInteger;
import javax.management.ObjectName;
@@ -85,10 +90,25 @@ public class StandardService extends Lif
private final Object connectorsLock = new Object();
/**
- *
+ * The list of executors held by the service.
*/
protected final ArrayList<Executor> executors = new ArrayList<>();
+ /**
+ * The number of threads available to process utility tasks in this service.
+ */
+ protected int utilityThreads = 0;
+
+ /**
+ * Utility executor with scheduling capabilities.
+ */
+ private ScheduledThreadPoolExecutor utilityExecutor = null;
+
+ /**
+ * Utility executor wrapper.
+ */
+ private ScheduledExecutorService utilityExecutorWrapper = null;
+
private Engine engine = null;
private ClassLoader parentClassLoader = null;
@@ -202,8 +222,65 @@ public class StandardService extends Lif
}
+ @Override
+ public int getUtilityThreads() {
+ return utilityThreads;
+ }
+
+
+ /**
+ * Handles the special values.
+ */
+ private int getUtilityThreadsInternal() {
+ int result = getUtilityThreads();
+ if (result > 0) {
+ return result;
+ }
+
+ // Zero == Runtime.getRuntime().availableProcessors()
+ // -ve == Runtime.getRuntime().availableProcessors() + value
+ // These two are the same
+ result = (Runtime.getRuntime().availableProcessors() / 2) + result;
+ if (result < 1) {
+ result = 1;
+ }
+ return result;
+ }
+
+ @Override
+ public void setUtilityThreads(int utilityThreads) {
+ if (utilityThreads < getUtilityThreadsInternal()) {
+ return;
+ }
+ int oldUtilityThreads = this.utilityThreads;
+ this.utilityThreads = utilityThreads;
+
+ // Use local copies to ensure thread safety
+ if (oldUtilityThreads != utilityThreads && utilityExecutor != null) {
+ reconfigureUtilityExecutor(getUtilityThreadsInternal());
+ }
+ }
+
+
+ private synchronized void reconfigureUtilityExecutor(int threads) {
+ if (utilityExecutor != null) {
+ utilityExecutor.setMaximumPoolSize(threads);
+ } else {
+ ScheduledThreadPoolExecutor scheduledThreadPoolExecutor =
+ new ScheduledThreadPoolExecutor(1, new UtilityThreadFactory(getName() + "-utility-"));
+ scheduledThreadPoolExecutor.setMaximumPoolSize(threads);
+ scheduledThreadPoolExecutor.setKeepAliveTime(10, TimeUnit.SECONDS);
+ scheduledThreadPoolExecutor.setRemoveOnCancelPolicy(true);
+ scheduledThreadPoolExecutor.setExecuteExistingDelayedTasksAfterShutdownPolicy(false);
+ utilityExecutor = scheduledThreadPoolExecutor;
+ utilityExecutorWrapper = new org.apache.tomcat.util.threads.ScheduledThreadPoolExecutor(utilityExecutor);
+ }
+ }
+
+
// --------------------------------------------------------- Public Methods
+
/**
* Add a new Connector to the set of defined Connectors, and associate it
* with this Service's Container.
@@ -500,6 +577,7 @@ public class StandardService extends Lif
executor.stop();
}
}
+
}
@@ -512,6 +590,9 @@ public class StandardService extends Lif
super.initInternal();
+ reconfigureUtilityExecutor(getUtilityThreadsInternal());
+ register(utilityExecutor, "type=UtilityExecutor");
+
if (engine != null) {
engine.init();
}
@@ -556,6 +637,12 @@ public class StandardService extends Lif
engine.destroy();
}
+ if (utilityExecutor != null) {
+ utilityExecutor.shutdownNow();
+ unregister("type=UtilityExecutor");
+ utilityExecutor = null;
+ }
+
super.destroyInternal();
}
@@ -613,4 +700,29 @@ public class StandardService extends Lif
public final String getObjectNameKeyProperties() {
return "type=Service";
}
+
+ private static class UtilityThreadFactory implements ThreadFactory {
+ private final ThreadGroup group;
+ private final AtomicInteger threadNumber = new AtomicInteger(1);
+ private final String namePrefix;
+
+ public UtilityThreadFactory(String namePrefix) {
+ SecurityManager s = System.getSecurityManager();
+ group = (s != null) ? s.getThreadGroup() : Thread.currentThread().getThreadGroup();
+ this.namePrefix = namePrefix;
+ }
+
+ @Override
+ public Thread newThread(Runnable r) {
+ Thread thread = new Thread(group, r, namePrefix + threadNumber.getAndIncrement());
+ thread.setDaemon(true);
+ return thread;
+ }
+ }
+
+ @Override
+ public ScheduledExecutorService getUtilityExecutor() {
+ return utilityExecutorWrapper;
+ }
+
}
Added: tomcat/trunk/java/org/apache/tomcat/util/threads/ScheduledThreadPoolExecutor.java
URL: http://svn.apache.org/viewvc/tomcat/trunk/java/org/apache/tomcat/util/threads/ScheduledThreadPoolExecutor.java?rev=1846116&view=auto
==============================================================================
--- tomcat/trunk/java/org/apache/tomcat/util/threads/ScheduledThreadPoolExecutor.java (added)
+++ tomcat/trunk/java/org/apache/tomcat/util/threads/ScheduledThreadPoolExecutor.java Thu Nov 8 10:17:43 2018
@@ -0,0 +1,141 @@
+/*
+ * 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.tomcat.util.threads;
+
+import java.util.Collection;
+import java.util.List;
+import java.util.concurrent.Callable;
+import java.util.concurrent.ExecutionException;
+import java.util.concurrent.Future;
+import java.util.concurrent.ScheduledExecutorService;
+import java.util.concurrent.ScheduledFuture;
+import java.util.concurrent.TimeUnit;
+import java.util.concurrent.TimeoutException;
+
+/**
+ * Class which wraps a ScheduledExecutorService, while preventing
+ * lifecycle and configuration operations.
+ */
+public class ScheduledThreadPoolExecutor implements ScheduledExecutorService {
+
+ protected final ScheduledExecutorService executor;
+
+ /**
+ * Builds a wrapper for the given executor.
+ * @param executor the wrapped executor
+ */
+ public ScheduledThreadPoolExecutor(ScheduledExecutorService executor) {
+ this.executor = executor;
+ }
+
+ @Override
+ public void shutdown() {
+ // Do nothing
+ }
+
+
+ @Override
+ public List<Runnable> shutdownNow() {
+ return null;
+ }
+
+ @Override
+ public boolean isShutdown() {
+ return executor.isShutdown();
+ }
+
+ @Override
+ public boolean isTerminated() {
+ return executor.isTerminated();
+ }
+
+ @Override
+ public boolean awaitTermination(long timeout, TimeUnit unit)
+ throws InterruptedException {
+ return executor.awaitTermination(timeout, unit);
+ }
+
+ @Override
+ public <T> Future<T> submit(Callable<T> task) {
+ return executor.submit(task);
+ }
+
+ @Override
+ public <T> Future<T> submit(Runnable task, T result) {
+ return executor.submit(task, result);
+ }
+
+ @Override
+ public Future<?> submit(Runnable task) {
+ return executor.submit(task);
+ }
+
+ @Override
+ public <T> List<Future<T>> invokeAll(Collection<? extends Callable<T>> tasks)
+ throws InterruptedException {
+ return executor.invokeAll(tasks);
+ }
+
+ @Override
+ public <T> List<Future<T>> invokeAll(Collection<? extends Callable<T>> tasks, long timeout,
+ TimeUnit unit) throws InterruptedException {
+ return executor.invokeAll(tasks, timeout, unit);
+ }
+
+ @Override
+ public <T> T invokeAny(Collection<? extends Callable<T>> tasks)
+ throws InterruptedException, ExecutionException {
+ return executor.invokeAny(tasks);
+ }
+
+ @Override
+ public <T> T invokeAny(Collection<? extends Callable<T>> tasks,
+ long timeout, TimeUnit unit)
+ throws InterruptedException, ExecutionException, TimeoutException {
+ return executor.invokeAny(tasks, timeout, unit);
+ }
+
+ @Override
+ public void execute(Runnable command) {
+ executor.execute(command);
+ }
+
+ @Override
+ public ScheduledFuture<?> schedule(Runnable command, long delay,
+ TimeUnit unit) {
+ return executor.schedule(command, delay, unit);
+ }
+
+ @Override
+ public <V> ScheduledFuture<V> schedule(Callable<V> callable, long delay,
+ TimeUnit unit) {
+ return executor.schedule(callable, delay, unit);
+ }
+
+ @Override
+ public ScheduledFuture<?> scheduleAtFixedRate(Runnable command,
+ long initialDelay, long period, TimeUnit unit) {
+ return executor.scheduleAtFixedRate(command, initialDelay, period, unit);
+ }
+
+ @Override
+ public ScheduledFuture<?> scheduleWithFixedDelay(Runnable command,
+ long initialDelay, long delay, TimeUnit unit) {
+ return executor.scheduleWithFixedDelay(command, initialDelay, delay, unit);
+ }
+
+}
Propchange: tomcat/trunk/java/org/apache/tomcat/util/threads/ScheduledThreadPoolExecutor.java
------------------------------------------------------------------------------
svn:eol-style = native
Modified: tomcat/trunk/test/org/apache/catalina/mbeans/TestRegistration.java
URL: http://svn.apache.org/viewvc/tomcat/trunk/test/org/apache/catalina/mbeans/TestRegistration.java?rev=1846116&r1=1846115&r2=1846116&view=diff
==============================================================================
--- tomcat/trunk/test/org/apache/catalina/mbeans/TestRegistration.java (original)
+++ tomcat/trunk/test/org/apache/catalina/mbeans/TestRegistration.java Thu Nov 8 10:17:43 2018
@@ -72,6 +72,7 @@ public class TestRegistration extends To
"Tomcat:type=Server",
"Tomcat:type=Service",
"Tomcat:type=StringCache",
+ "Tomcat:type=UtilityExecutor",
"Tomcat:type=Valve,name=StandardEngineValve",
};
}
Modified: tomcat/trunk/webapps/docs/changelog.xml
URL: http://svn.apache.org/viewvc/tomcat/trunk/webapps/docs/changelog.xml?rev=1846116&r1=1846115&r2=1846116&view=diff
==============================================================================
--- tomcat/trunk/webapps/docs/changelog.xml (original)
+++ tomcat/trunk/webapps/docs/changelog.xml Thu Nov 8 10:17:43 2018
@@ -64,6 +64,10 @@
Include German translations for the Manager application in the standard
Tomcat distribution. (markt)
</fix>
+ <add>
+ Add a scheduled executor to the Service, which can be used to
+ process periodic utility tasks. (remm)
+ </add>
</changelog>
</subsection>
</section>
Modified: tomcat/trunk/webapps/docs/config/service.xml
URL: http://svn.apache.org/viewvc/tomcat/trunk/webapps/docs/config/service.xml?rev=1846116&r1=1846115&r2=1846116&view=diff
==============================================================================
--- tomcat/trunk/webapps/docs/config/service.xml (original)
+++ tomcat/trunk/webapps/docs/config/service.xml Thu Nov 8 10:17:43 2018
@@ -68,6 +68,17 @@
must be unique.</p>
</attribute>
+ <attribute name="startStopThreads" required="false">
+ <p>The number of threads this <strong>Service</strong> will use for
+ various utility tasks, including recurring ones. The special value
+ of 0 will result in the value of
+ <code>Runtime.getRuntime().availableProcessors()/2</code> being
+ used. Negative values will result in
+ <code>Runtime.getRuntime().availableProcessors()/2 + value</code> being
+ used unless this is less than 1 in which case 1 thread will be used.
+ </p>
+ </attribute>
+
</attributes>
</subsection>
---------------------------------------------------------------------
To unsubscribe, e-mail: dev-unsubscribe@tomcat.apache.org
For additional commands, e-mail: dev-help@tomcat.apache.org
Re: svn commit: r1846116 - in /tomcat/trunk: java/org/apache/catalina/
java/org/apache/catalina/core/ java/org/apache/tomcat/util/threads/
test/org/apache/catalina/mbeans/ webapps/docs/ webapps/docs/config/
Posted by Rémy Maucherat <re...@apache.org>.
On Fri, Nov 23, 2018 at 1:05 PM Mark Thomas <ma...@apache.org> wrote:
> On 08/11/2018 10:17, remm@apache.org wrote:
> > Author: remm
> > Date: Thu Nov 8 10:17:43 2018
> > New Revision: 1846116
> >
> > URL: http://svn.apache.org/viewvc?rev=1846116&view=rev
> > Log:
> > Add a scheduled executor service to the Service, which can be used to
> process utility tasks including periodic ones.
> > Add a simple wrapper to prevent random lifecycle and configuration
> operations.
> > Add a bean for it.
>
> <snip/>
>
> > Modified: tomcat/trunk/java/org/apache/catalina/core/StandardService.java
> > URL:
> http://svn.apache.org/viewvc/tomcat/trunk/java/org/apache/catalina/core/StandardService.java?rev=1846116&r1=1846115&r2=1846116&view=diff
>
> <snip/>
>
> > + private synchronized void reconfigureUtilityExecutor(int threads) {
> > + if (utilityExecutor != null) {
> > + utilityExecutor.setMaximumPoolSize(threads);
>
> I'm seeing a SpotBugs warning on the above line that calling
> setMaximumPoolSize() is a NO-OP. From the Javadoc:
>
> <quote>
> In particular, because it acts as a fixed-sized pool using {@code
> corePoolSize} threads and an unbounded queue, adjustments to {@code
> maximumPoolSize} have no useful effect.
> </quote>
>
> Should this be calling setCorePoolSize() ?
>
Ok, I will make adjustments then. Another bad idea as well: using
allowCoreThreadTimeOut, all is does is endlessly stopping and restarting
immediately the core threads.
Rémy
Re: svn commit: r1846116 - in /tomcat/trunk:
java/org/apache/catalina/ java/org/apache/catalina/core/
java/org/apache/tomcat/util/threads/ test/org/apache/catalina/mbeans/
webapps/docs/ webapps/docs/config/
Posted by Mark Thomas <ma...@apache.org>.
On 08/11/2018 10:17, remm@apache.org wrote:
> Author: remm
> Date: Thu Nov 8 10:17:43 2018
> New Revision: 1846116
>
> URL: http://svn.apache.org/viewvc?rev=1846116&view=rev
> Log:
> Add a scheduled executor service to the Service, which can be used to process utility tasks including periodic ones.
> Add a simple wrapper to prevent random lifecycle and configuration operations.
> Add a bean for it.
<snip/>
> Modified: tomcat/trunk/java/org/apache/catalina/core/StandardService.java
> URL: http://svn.apache.org/viewvc/tomcat/trunk/java/org/apache/catalina/core/StandardService.java?rev=1846116&r1=1846115&r2=1846116&view=diff
<snip/>
> + private synchronized void reconfigureUtilityExecutor(int threads) {
> + if (utilityExecutor != null) {
> + utilityExecutor.setMaximumPoolSize(threads);
I'm seeing a SpotBugs warning on the above line that calling
setMaximumPoolSize() is a NO-OP. From the Javadoc:
<quote>
In particular, because it acts as a fixed-sized pool using {@code
corePoolSize} threads and an unbounded queue, adjustments to {@code
maximumPoolSize} have no useful effect.
</quote>
Should this be calling setCorePoolSize() ?
Mark
> + } else {
> + ScheduledThreadPoolExecutor scheduledThreadPoolExecutor =
> + new ScheduledThreadPoolExecutor(1, new UtilityThreadFactory(getName() + "-utility-"));
> + scheduledThreadPoolExecutor.setMaximumPoolSize(threads);
> + scheduledThreadPoolExecutor.setKeepAliveTime(10, TimeUnit.SECONDS);
> + scheduledThreadPoolExecutor.setRemoveOnCancelPolicy(true);
> + scheduledThreadPoolExecutor.setExecuteExistingDelayedTasksAfterShutdownPolicy(false);
> + utilityExecutor = scheduledThreadPoolExecutor;
> + utilityExecutorWrapper = new org.apache.tomcat.util.threads.ScheduledThreadPoolExecutor(utilityExecutor);
> + }
---------------------------------------------------------------------
To unsubscribe, e-mail: dev-unsubscribe@tomcat.apache.org
For additional commands, e-mail: dev-help@tomcat.apache.org