This is an automated email from the ASF dual-hosted git repository.
remm pushed a commit to branch 9.0.x
in repository https://gitbox.apache.org/repos/asf/tomcat.git
The following commit(s) were added to refs/heads/9.0.x by this push:
new 0640663aa9 Implement ExecutorService
0640663aa9 is described below
commit 0640663aa94ea79cd70729fce23ac9378a82b57e
Author: remm <[email protected]>
AuthorDate: Fri Mar 1 09:50:55 2024 +0100
Implement ExecutorService
This allows better interactions with NIO2.
BZ68692
---
.../catalina/core/StandardThreadExecutor.java | 121 +++++++++++++++++++-
.../core/StandardVirtualThreadExecutor.java | 122 ++++++++++++++++++++-
.../apache/tomcat/util/net/LocalStrings.properties | 1 +
java/org/apache/tomcat/util/net/Nio2Endpoint.java | 2 +
.../util/threads/ScheduledThreadPoolExecutor.java | 3 +-
webapps/docs/changelog.xml | 7 +-
6 files changed, 251 insertions(+), 5 deletions(-)
diff --git a/java/org/apache/catalina/core/StandardThreadExecutor.java
b/java/org/apache/catalina/core/StandardThreadExecutor.java
index 4973886889..0974260b0a 100644
--- a/java/org/apache/catalina/core/StandardThreadExecutor.java
+++ b/java/org/apache/catalina/core/StandardThreadExecutor.java
@@ -16,7 +16,15 @@
*/
package org.apache.catalina.core;
+import java.util.Collection;
+import java.util.Collections;
+import java.util.List;
+import java.util.concurrent.Callable;
+import java.util.concurrent.ExecutionException;
+import java.util.concurrent.ExecutorService;
+import java.util.concurrent.Future;
import java.util.concurrent.TimeUnit;
+import java.util.concurrent.TimeoutException;
import org.apache.catalina.Executor;
import org.apache.catalina.LifecycleException;
@@ -28,7 +36,7 @@ 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 {
+public class StandardThreadExecutor extends LifecycleMBeanBase implements
Executor, ExecutorService, ResizableExecutor {
protected static final StringManager sm =
StringManager.getManager(StandardThreadExecutor.class);
@@ -304,4 +312,115 @@ public class StandardThreadExecutor extends
LifecycleMBeanBase implements Execut
protected String getObjectNameKeyProperties() {
return "type=Executor,name=" + getName();
}
+
+
+ @Override
+ public void shutdown() {
+ // Controlled by Lifecycle instead
+ }
+
+
+ @Override
+ public List<Runnable> shutdownNow() {
+ // Controlled by Lifecycle instead
+ return Collections.emptyList();
+ }
+
+
+ @Override
+ public boolean isShutdown() {
+ if (executor != null) {
+ return executor.isShutdown();
+ } else {
+ throw new
IllegalStateException(sm.getString("standardThreadExecutor.notStarted"));
+ }
+ }
+
+
+ @Override
+ public boolean isTerminated() {
+ if (executor != null) {
+ return executor.isTerminated();
+ } else {
+ throw new
IllegalStateException(sm.getString("standardThreadExecutor.notStarted"));
+ }
+ }
+
+
+ @Override
+ public boolean awaitTermination(long timeout, TimeUnit unit) throws
InterruptedException {
+ return false;
+ }
+
+
+ @Override
+ public <T> Future<T> submit(Callable<T> task) {
+ if (executor != null) {
+ return executor.submit(task);
+ } else {
+ throw new
IllegalStateException(sm.getString("standardThreadExecutor.notStarted"));
+ }
+ }
+
+
+ @Override
+ public <T> Future<T> submit(Runnable task, T result) {
+ if (executor != null) {
+ return executor.submit(task, result);
+ } else {
+ throw new
IllegalStateException(sm.getString("standardThreadExecutor.notStarted"));
+ }
+ }
+
+
+ @Override
+ public Future<?> submit(Runnable task) {
+ if (executor != null) {
+ return executor.submit(task);
+ } else {
+ throw new
IllegalStateException(sm.getString("standardThreadExecutor.notStarted"));
+ }
+ }
+
+
+ @Override
+ public <T> List<Future<T>> invokeAll(Collection<? extends Callable<T>>
tasks) throws InterruptedException {
+ if (executor != null) {
+ return executor.invokeAll(tasks);
+ } else {
+ throw new
IllegalStateException(sm.getString("standardThreadExecutor.notStarted"));
+ }
+ }
+
+
+ @Override
+ public <T> List<Future<T>> invokeAll(Collection<? extends Callable<T>>
tasks, long timeout, TimeUnit unit)
+ throws InterruptedException {
+ if (executor != null) {
+ return executor.invokeAll(tasks, timeout, unit);
+ } else {
+ throw new
IllegalStateException(sm.getString("standardThreadExecutor.notStarted"));
+ }
+ }
+
+
+ @Override
+ public <T> T invokeAny(Collection<? extends Callable<T>> tasks) throws
InterruptedException, ExecutionException {
+ if (executor != null) {
+ return executor.invokeAny(tasks);
+ } else {
+ throw new
IllegalStateException(sm.getString("standardThreadExecutor.notStarted"));
+ }
+ }
+
+
+ @Override
+ public <T> T invokeAny(Collection<? extends Callable<T>> tasks, long
timeout, TimeUnit unit)
+ throws InterruptedException, ExecutionException, TimeoutException {
+ if (executor != null) {
+ return executor.invokeAny(tasks, timeout, unit);
+ } else {
+ throw new
IllegalStateException(sm.getString("standardThreadExecutor.notStarted"));
+ }
+ }
}
diff --git a/java/org/apache/catalina/core/StandardVirtualThreadExecutor.java
b/java/org/apache/catalina/core/StandardVirtualThreadExecutor.java
index eb6255f939..0c271419ef 100644
--- a/java/org/apache/catalina/core/StandardVirtualThreadExecutor.java
+++ b/java/org/apache/catalina/core/StandardVirtualThreadExecutor.java
@@ -16,7 +16,15 @@
*/
package org.apache.catalina.core;
+import java.util.Collection;
+import java.util.Collections;
+import java.util.List;
+import java.util.concurrent.Callable;
+import java.util.concurrent.ExecutionException;
+import java.util.concurrent.ExecutorService;
+import java.util.concurrent.Future;
import java.util.concurrent.TimeUnit;
+import java.util.concurrent.TimeoutException;
import org.apache.catalina.Executor;
import org.apache.catalina.LifecycleException;
@@ -29,12 +37,12 @@ import org.apache.tomcat.util.threads.VirtualThreadExecutor;
/**
* An executor that uses a new virtual thread for each task.
*/
-public class StandardVirtualThreadExecutor extends LifecycleMBeanBase
implements Executor {
+public class StandardVirtualThreadExecutor extends LifecycleMBeanBase
implements Executor, ExecutorService {
private static final StringManager sm =
StringManager.getManager(StandardVirtualThreadExecutor.class);
private String name;
- private java.util.concurrent.Executor executor;
+ private java.util.concurrent.ExecutorService executor;
private String namePrefix = "tomcat-virt-";
public void setName(String name) {
@@ -100,4 +108,114 @@ public class StandardVirtualThreadExecutor extends
LifecycleMBeanBase implements
protected String getObjectNameKeyProperties() {
return "type=Executor,name=" + getName();
}
+
+ @Override
+ public void shutdown() {
+ // Controlled by Lifecycle instead
+ }
+
+
+ @Override
+ public List<Runnable> shutdownNow() {
+ // Controlled by Lifecycle instead
+ return Collections.emptyList();
+ }
+
+
+ @Override
+ public boolean isShutdown() {
+ if (executor != null) {
+ return executor.isShutdown();
+ } else {
+ throw new
IllegalStateException(sm.getString("standardThreadExecutor.notStarted"));
+ }
+ }
+
+
+ @Override
+ public boolean isTerminated() {
+ if (executor != null) {
+ return executor.isTerminated();
+ } else {
+ throw new
IllegalStateException(sm.getString("standardThreadExecutor.notStarted"));
+ }
+ }
+
+
+ @Override
+ public boolean awaitTermination(long timeout, TimeUnit unit) throws
InterruptedException {
+ return false;
+ }
+
+
+ @Override
+ public <T> Future<T> submit(Callable<T> task) {
+ if (executor != null) {
+ return executor.submit(task);
+ } else {
+ throw new
IllegalStateException(sm.getString("standardThreadExecutor.notStarted"));
+ }
+ }
+
+
+ @Override
+ public <T> Future<T> submit(Runnable task, T result) {
+ if (executor != null) {
+ return executor.submit(task, result);
+ } else {
+ throw new
IllegalStateException(sm.getString("standardThreadExecutor.notStarted"));
+ }
+ }
+
+
+ @Override
+ public Future<?> submit(Runnable task) {
+ if (executor != null) {
+ return executor.submit(task);
+ } else {
+ throw new
IllegalStateException(sm.getString("standardThreadExecutor.notStarted"));
+ }
+ }
+
+
+ @Override
+ public <T> List<Future<T>> invokeAll(Collection<? extends Callable<T>>
tasks) throws InterruptedException {
+ if (executor != null) {
+ return executor.invokeAll(tasks);
+ } else {
+ throw new
IllegalStateException(sm.getString("standardThreadExecutor.notStarted"));
+ }
+ }
+
+
+ @Override
+ public <T> List<Future<T>> invokeAll(Collection<? extends Callable<T>>
tasks, long timeout, TimeUnit unit)
+ throws InterruptedException {
+ if (executor != null) {
+ return executor.invokeAll(tasks, timeout, unit);
+ } else {
+ throw new
IllegalStateException(sm.getString("standardThreadExecutor.notStarted"));
+ }
+ }
+
+
+ @Override
+ public <T> T invokeAny(Collection<? extends Callable<T>> tasks) throws
InterruptedException, ExecutionException {
+ if (executor != null) {
+ return executor.invokeAny(tasks);
+ } else {
+ throw new
IllegalStateException(sm.getString("standardThreadExecutor.notStarted"));
+ }
+ }
+
+
+ @Override
+ public <T> T invokeAny(Collection<? extends Callable<T>> tasks, long
timeout, TimeUnit unit)
+ throws InterruptedException, ExecutionException, TimeoutException {
+ if (executor != null) {
+ return executor.invokeAny(tasks, timeout, unit);
+ } else {
+ throw new
IllegalStateException(sm.getString("standardThreadExecutor.notStarted"));
+ }
+ }
}
\ No newline at end of file
diff --git a/java/org/apache/tomcat/util/net/LocalStrings.properties
b/java/org/apache/tomcat/util/net/LocalStrings.properties
index 20e8ed1a4d..0945510492 100644
--- a/java/org/apache/tomcat/util/net/LocalStrings.properties
+++ b/java/org/apache/tomcat/util/net/LocalStrings.properties
@@ -110,6 +110,7 @@ endpoint.nio.stopLatchAwaitFail=The pollers did not stop
within the expected tim
endpoint.nio.stopLatchAwaitInterrupted=This thread was interrupted while
waiting for the pollers to stop
endpoint.nio.timeoutCme=Exception during processing of timeouts. The code has
been checked repeatedly and no concurrent modification has been found. If you
are able to repeat this error please open a Tomcat bug and provide the steps to
reproduce.
endpoint.nio2.exclusiveExecutor=The NIO2 connector requires an exclusive
executor to operate properly on shutdown
+endpoint.nio2.executorService=The NIO2 connector requires an executor service,
the internal JVM threads will be used
endpoint.noSslHostConfig=No SSLHostConfig element was found with the hostName
[{0}] to match the defaultSSLHostConfigName for the connector [{1}]
endpoint.noSslHostName=No host name was provided for the SSL host configuration
endpoint.poll.error=Unexpected poller error
diff --git a/java/org/apache/tomcat/util/net/Nio2Endpoint.java
b/java/org/apache/tomcat/util/net/Nio2Endpoint.java
index b2966ac5b6..21b9f8acfb 100644
--- a/java/org/apache/tomcat/util/net/Nio2Endpoint.java
+++ b/java/org/apache/tomcat/util/net/Nio2Endpoint.java
@@ -131,6 +131,8 @@ public class Nio2Endpoint extends
AbstractJsseEndpoint<Nio2Channel,AsynchronousS
}
if (getExecutor() instanceof ExecutorService) {
threadGroup =
AsynchronousChannelGroup.withThreadPool((ExecutorService) getExecutor());
+ } else {
+ log.info(sm.getString("endpoint.nio2.executorService"));
}
// AsynchronousChannelGroup needs exclusive access to its executor
service
if (!internalExecutor) {
diff --git
a/java/org/apache/tomcat/util/threads/ScheduledThreadPoolExecutor.java
b/java/org/apache/tomcat/util/threads/ScheduledThreadPoolExecutor.java
index 98d10cc5b4..45d9c93c50 100644
--- a/java/org/apache/tomcat/util/threads/ScheduledThreadPoolExecutor.java
+++ b/java/org/apache/tomcat/util/threads/ScheduledThreadPoolExecutor.java
@@ -17,6 +17,7 @@
package org.apache.tomcat.util.threads;
import java.util.Collection;
+import java.util.Collections;
import java.util.List;
import java.util.concurrent.Callable;
import java.util.concurrent.ExecutionException;
@@ -50,7 +51,7 @@ public class ScheduledThreadPoolExecutor implements
ScheduledExecutorService {
@Override
public List<Runnable> shutdownNow() {
- return null;
+ return Collections.emptyList();
}
@Override
diff --git a/webapps/docs/changelog.xml b/webapps/docs/changelog.xml
index 816015a329..928d515442 100644
--- a/webapps/docs/changelog.xml
+++ b/webapps/docs/changelog.xml
@@ -116,7 +116,12 @@
<code>OutputStream</code>. Ensure use of either once the response has
been recycled triggers a <code>NullPointerException</code> provided
that
<code>discardFacades</code> is configured with the default value of
- <code>true</code>.
+ <code>true</code>. (markt)
+ </fix>
+ <fix>
+ <bug>68692</bug>: The standard thread pool implementations that are
+ configured using the <code>Executor</code> element now implement
+ <code>ExecutorService</code> for better support NIO2. (remm)
</fix>
</changelog>
</subsection>
---------------------------------------------------------------------
To unsubscribe, e-mail: [email protected]
For additional commands, e-mail: [email protected]