You are viewing a plain text version of this content. The canonical link for it is here.
Posted to commits@commons.apache.org by tv...@apache.org on 2020/04/12 21:57:47 UTC

[commons-jcs] 04/05: Better concurrency

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

tv pushed a commit to branch master
in repository https://gitbox.apache.org/repos/asf/commons-jcs.git

commit ec4c3e0739eb9bdb39c57febf93ce988f80134e2
Author: Thomas Vandahl <tv...@apache.org>
AuthorDate: Sun Apr 12 23:56:52 2020 +0200

    Better concurrency
---
 .../jcs/utils/threadpool/ThreadPoolManager.java    | 112 ++++++++-------------
 .../threadpool/ThreadPoolManagerUnitTest.java      |   4 +-
 2 files changed, 46 insertions(+), 70 deletions(-)

diff --git a/commons-jcs-core/src/main/java/org/apache/commons/jcs/utils/threadpool/ThreadPoolManager.java b/commons-jcs-core/src/main/java/org/apache/commons/jcs/utils/threadpool/ThreadPoolManager.java
index ddcde27..e492b0c 100644
--- a/commons-jcs-core/src/main/java/org/apache/commons/jcs/utils/threadpool/ThreadPoolManager.java
+++ b/commons-jcs-core/src/main/java/org/apache/commons/jcs/utils/threadpool/ThreadPoolManager.java
@@ -1,26 +1,9 @@
 package org.apache.commons.jcs.utils.threadpool;
 
-/*
- * 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.
- */
-
-import java.util.ArrayList;
+import java.util.Iterator;
+import java.util.Map;
 import java.util.Properties;
+import java.util.Set;
 import java.util.concurrent.BlockingQueue;
 import java.util.concurrent.ConcurrentHashMap;
 import java.util.concurrent.ExecutorService;
@@ -59,6 +42,9 @@ public class ThreadPoolManager
     /** The default config, created using property defaults if present, else those above. */
     private PoolConfiguration defaultConfig;
 
+    /** The default scheduler config, created using property defaults if present, else those above. */
+    private PoolConfiguration defaultSchedulerConfig;
+
     /** the root property name */
     private static final String PROP_NAME_ROOT = "thread_pool";
 
@@ -77,9 +63,6 @@ public class ThreadPoolManager
      */
     private static volatile Properties props = null;
 
-    /** singleton instance */
-    private static ThreadPoolManager INSTANCE = null;
-
     /** Map of names to pools. */
     private ConcurrentHashMap<String, ExecutorService> pools;
 
@@ -87,6 +70,14 @@ public class ThreadPoolManager
     private ConcurrentHashMap<String, ScheduledExecutorService> schedulerPools;
 
     /**
+     * The ThreadPoolManager instance (holder pattern)
+     */
+    private static class ThreadPoolManagerHolder
+    {
+        static final ThreadPoolManager INSTANCE = new ThreadPoolManager();
+    }
+
+    /**
      * No instances please. This is a singleton.
      */
     private ThreadPoolManager()
@@ -188,47 +179,44 @@ public class ThreadPoolManager
      * <p>
      * @return The single instance of the ThreadPoolManager
      */
-    public static synchronized ThreadPoolManager getInstance()
+    public static ThreadPoolManager getInstance()
     {
-        if ( INSTANCE == null )
-        {
-            INSTANCE = new ThreadPoolManager();
-        }
-        return INSTANCE;
+        return ThreadPoolManagerHolder.INSTANCE;
     }
 
     /**
      * Dispose of the instance of the ThreadPoolManger and shut down all thread pools
      */
-    public static synchronized void dispose()
+    public static void dispose()
     {
-        if ( INSTANCE != null )
+        for ( Iterator<Map.Entry<String, ExecutorService>> i =
+                getInstance().pools.entrySet().iterator(); i.hasNext(); )
         {
-            for ( ExecutorService pool : INSTANCE.pools.values() )
+            Map.Entry<String, ExecutorService> entry = i.next();
+            try
             {
-                try
-                {
-                    pool.shutdownNow();
-                }
-                catch (Throwable t)
-                {
-                    log.warn("Failed to close pool {0}", pool, t);
-                }
+                entry.getValue().shutdownNow();
             }
-
-            for ( ScheduledExecutorService pool : INSTANCE.schedulerPools.values() )
+            catch (Throwable t)
             {
-                try
-                {
-                    pool.shutdownNow();
-                }
-                catch (Throwable t)
-                {
-                    log.warn("Failed to close pool {0}", pool, t);
-                }
+                log.warn("Failed to close pool {0}", entry.getKey(), t);
             }
+            i.remove();
+        }
 
-            INSTANCE = null;
+        for ( Iterator<Map.Entry<String, ScheduledExecutorService>> i =
+                getInstance().schedulerPools.entrySet().iterator(); i.hasNext(); )
+        {
+            Map.Entry<String, ScheduledExecutorService> entry = i.next();
+            try
+            {
+                entry.getValue().shutdownNow();
+            }
+            catch (Throwable t)
+            {
+                log.warn("Failed to close pool {0}", entry.getKey(), t);
+            }
+            i.remove();
         }
     }
 
@@ -245,7 +233,7 @@ public class ThreadPoolManager
     {
     	ExecutorService pool = pools.computeIfAbsent(name, key -> {
             log.debug( "Creating pool for name [{0}]", key );
-            PoolConfiguration config = loadConfig( PROP_NAME_ROOT + "." + key );
+            PoolConfiguration config = loadConfig( PROP_NAME_ROOT + "." + key, defaultConfig );
             return createPool( config, "JCS-ThreadPoolManager-" + key + "-" );
     	});
 
@@ -265,7 +253,6 @@ public class ThreadPoolManager
     {
     	ScheduledExecutorService pool = schedulerPools.computeIfAbsent(name, key -> {
             log.debug( "Creating scheduler pool for name [{0}]", key );
-            PoolConfiguration defaultSchedulerConfig = loadConfig( DEFAULT_PROP_NAME_SCHEDULER_ROOT );
             PoolConfiguration config = loadConfig( PROP_NAME_SCHEDULER_ROOT + "." + key,
                     defaultSchedulerConfig );
             return createSchedulerPool( config, "JCS-ThreadPoolManager-" + key + "-", Thread.NORM_PRIORITY );
@@ -279,9 +266,9 @@ public class ThreadPoolManager
      * <p>
      * @return ArrayList of string names
      */
-    public ArrayList<String> getPoolNames()
+    protected Set<String> getPoolNames()
     {
-        return new ArrayList<>(pools.keySet());
+        return pools.keySet();
     }
 
     /**
@@ -309,19 +296,8 @@ public class ThreadPoolManager
         }
 
         // set initial default and then override if new settings are available
-        defaultConfig = new PoolConfiguration();
-        defaultConfig = loadConfig( DEFAULT_PROP_NAME_ROOT );
-    }
-
-    /**
-     * Configures the PoolConfiguration settings.
-     * <p>
-     * @param root the configuration key prefix
-     * @return PoolConfiguration
-     */
-    private PoolConfiguration loadConfig( String root )
-    {
-    	return loadConfig(root, defaultConfig);
+        defaultConfig = loadConfig( DEFAULT_PROP_NAME_ROOT, new PoolConfiguration() );
+        defaultSchedulerConfig = loadConfig( DEFAULT_PROP_NAME_SCHEDULER_ROOT, new PoolConfiguration() );
     }
 
     /**
diff --git a/commons-jcs-core/src/test/java/org/apache/commons/jcs/utils/threadpool/ThreadPoolManagerUnitTest.java b/commons-jcs-core/src/test/java/org/apache/commons/jcs/utils/threadpool/ThreadPoolManagerUnitTest.java
index 753e775..3831954 100644
--- a/commons-jcs-core/src/test/java/org/apache/commons/jcs/utils/threadpool/ThreadPoolManagerUnitTest.java
+++ b/commons-jcs-core/src/test/java/org/apache/commons/jcs/utils/threadpool/ThreadPoolManagerUnitTest.java
@@ -19,8 +19,8 @@ package org.apache.commons.jcs.utils.threadpool;
  * under the License.
  */
 
-import java.util.ArrayList;
 import java.util.Properties;
+import java.util.Set;
 import java.util.concurrent.ExecutorService;
 
 import org.apache.commons.jcs.utils.props.PropertyLoader;
@@ -80,7 +80,7 @@ public class ThreadPoolManagerUnitTest
         String poolName2 = "testGetPoolNames2";
         mgr.getExecutorService( poolName2 );
 
-        ArrayList<String> names = mgr.getPoolNames();
+        Set<String> names = mgr.getPoolNames();
         assertTrue( "Should have name in list.", names.contains( poolName1 ) );
         assertTrue( "Should have name in list.", names.contains( poolName2 ) );
     }