This is an automated email from the ASF dual-hosted git repository.

robertlazarski pushed a commit to branch master
in repository https://gitbox.apache.org/repos/asf/axis-axis2-java-core.git

commit b26f550516b9b9f3fbefa9364d71acce91ca91d1
Author: Robert Lazarski <[email protected]>
AuthorDate: Sat Feb 14 10:33:07 2026 -1000

    Fix AXIS2-5696: Prevent ThreadPool thread leaks by enabling core thread 
timeout
    
    Enable allowCoreThreadTimeOut(true) on the ThreadPoolExecutor, which was
    commented out with a JDK 1.6 FIXME that is long obsolete. Idle core threads
    now terminate after the 10-second keepAlive period instead of persisting
    indefinitely. Also shut down the ThreadPool in 
ConfigurationContext.terminate()
    as defense-in-depth.
    
    Co-Authored-By: Claude Opus 4.6 <[email protected]>
---
 .../apache/axis2/context/ConfigurationContext.java |  4 +++
 .../apache/axis2/util/threadpool/ThreadPool.java   |  3 +-
 .../axis2/util/threadpool/TestThreadPool.java      | 36 +++++++++++++++++++++-
 3 files changed, 40 insertions(+), 3 deletions(-)

diff --git 
a/modules/kernel/src/org/apache/axis2/context/ConfigurationContext.java 
b/modules/kernel/src/org/apache/axis2/context/ConfigurationContext.java
index 23b417f6d2..69ebc4eb8a 100644
--- a/modules/kernel/src/org/apache/axis2/context/ConfigurationContext.java
+++ b/modules/kernel/src/org/apache/axis2/context/ConfigurationContext.java
@@ -737,6 +737,10 @@ public class ConfigurationContext extends AbstractContext {
      */
     public void terminate() throws AxisFault {
         shutdownModulesAndServices();
+        // AXIS2-5696: Shut down the thread pool to prevent thread leaks
+        if (threadPool instanceof ThreadPool) {
+            ((ThreadPool) threadPool).safeShutDown();
+        }
         if (listenerManager != null) {
             listenerManager.destroy();
         }
diff --git 
a/modules/kernel/src/org/apache/axis2/util/threadpool/ThreadPool.java 
b/modules/kernel/src/org/apache/axis2/util/threadpool/ThreadPool.java
index a6d4a753ec..bb05949922 100644
--- a/modules/kernel/src/org/apache/axis2/util/threadpool/ThreadPool.java
+++ b/modules/kernel/src/org/apache/axis2/util/threadpool/ThreadPool.java
@@ -114,8 +114,7 @@ public class ThreadPool implements ThreadFactory {
                     TimeUnit.SECONDS, new LinkedBlockingQueue(),
                     new DefaultThreadFactory(name, daemon, priority));
         }
-// FIXME: This API is only in JDK 1.6 - Use reflection?        
-//        rc.allowCoreThreadTimeOut(true);
+        rc.allowCoreThreadTimeOut(true);
         return rc;
     }
 
diff --git 
a/modules/kernel/test/org/apache/axis2/util/threadpool/TestThreadPool.java 
b/modules/kernel/test/org/apache/axis2/util/threadpool/TestThreadPool.java
index e3fe71ed66..4257cc67bf 100644
--- a/modules/kernel/test/org/apache/axis2/util/threadpool/TestThreadPool.java
+++ b/modules/kernel/test/org/apache/axis2/util/threadpool/TestThreadPool.java
@@ -24,6 +24,8 @@ import org.apache.axis2.AxisFault;
 
 import java.util.ArrayList;
 import java.util.List;
+import java.util.concurrent.ThreadPoolExecutor;
+import java.util.concurrent.TimeUnit;
 
 public class TestThreadPool extends AbstractTestCase {
     /**
@@ -46,7 +48,7 @@ public class TestThreadPool extends AbstractTestCase {
     }
 
 
-    public void testPool() throws AxisFault {
+    public void testPool() throws Exception {
         ThreadPool tPool = new ThreadPool();
         List workerList = new ArrayList();
 
@@ -57,6 +59,8 @@ public class TestThreadPool extends AbstractTestCase {
         }
 
         tPool.safeShutDown();
+        ThreadPoolExecutor executor = (ThreadPoolExecutor) tPool.getExecutor();
+        executor.awaitTermination(5, TimeUnit.SECONDS);
 
         for (int i = 0; i < 5; i++) {
             assertEquals(true, ((TestWorker) workerList.get(i)).isWorkDone());
@@ -64,4 +68,34 @@ public class TestThreadPool extends AbstractTestCase {
 
     }
 
+    /**
+     * Test that core threads time out and terminate after the keepAlive period
+     * when allowCoreThreadTimeOut is enabled (AXIS2-5696).
+     */
+    public void testCoreThreadsTimeOut() throws Exception {
+        ThreadPool tPool = new ThreadPool();
+        ThreadPoolExecutor executor = (ThreadPoolExecutor) tPool.getExecutor();
+
+        // Verify allowCoreThreadTimeOut is enabled
+        assertTrue("allowCoreThreadTimeOut should be enabled",
+                executor.allowsCoreThreadTimeOut());
+
+        // Submit a task directly to the executor to create a core thread
+        TestWorker worker = new TestWorker();
+        executor.execute(worker);
+
+        // Wait briefly for the task to complete and the thread to be created
+        Thread.sleep(500);
+        assertTrue("Worker should have completed", worker.isWorkDone());
+        assertTrue("Pool should have at least one thread",
+                executor.getPoolSize() > 0);
+
+        // Wait for keepAlive timeout (10 seconds) plus buffer
+        Thread.sleep(12_000);
+
+        // Core threads should have timed out and terminated
+        assertEquals("All core threads should have timed out", 0,
+                executor.getPoolSize());
+    }
+
 }

Reply via email to