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 <[email protected]> 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 ) ); }
