Merge selected bugfixes from trunk into 2.1-RC branch

git-svn-id: https://svn.apache.org/repos/asf/commons/proper/jcs/branches/commons-jcs-2.1-RC@1781732 13f79535-47bb-0310-9956-ffa450edef68
diff --git a/README.md b/README.md
index 49374d7..78ebaca 100644
--- a/README.md
+++ b/README.md
@@ -62,7 +62,7 @@
 <dependency>
   <groupId>org.apache.commons</groupId>
   <artifactId>commons-jcs</artifactId>
-  <version>2.0</version>
+  <version>2.1</version>
 </dependency>
 ```
 
diff --git a/commons-jcs-core/pom.xml b/commons-jcs-core/pom.xml
index 480dfae..ea02976 100644
--- a/commons-jcs-core/pom.xml
+++ b/commons-jcs-core/pom.xml
@@ -33,9 +33,9 @@
   <name>Apache Commons JCS :: Core</name>
 
   <scm>
-    <connection>scm:svn:http://svn.apache.org/repos/asf/commons/proper/jcs/trunk/commons-jcs-core</connection>
-    <developerConnection>scm:svn:https://svn.apache.org/repos/asf/commons/proper/jcs/trunk/commons-jcs-core</developerConnection>
-    <url>http://svn.apache.org/viewvc/commons/proper/jcs/trunk/commons-jcs-core</url>
+    <connection>scm:svn:http://svn.apache.org/repos/asf/commons/proper/jcs/branches/commons-jcs-2.1-RC/commons-jcs-core</connection>
+    <developerConnection>scm:svn:https://svn.apache.org/repos/asf/commons/proper/jcs/branches/commons-jcs-2.1-RC/commons-jcs-core</developerConnection>
+    <url>http://svn.apache.org/viewvc/commons/proper/jcs/branches/commons-jcs-2.1-RC/commons-jcs-core</url>
   </scm>
 
   <properties>
diff --git a/commons-jcs-core/src/main/java/org/apache/commons/jcs/auxiliary/remote/AbstractRemoteAuxiliaryCache.java b/commons-jcs-core/src/main/java/org/apache/commons/jcs/auxiliary/remote/AbstractRemoteAuxiliaryCache.java
index 0b3d656..653220d 100644
--- a/commons-jcs-core/src/main/java/org/apache/commons/jcs/auxiliary/remote/AbstractRemoteAuxiliaryCache.java
+++ b/commons-jcs-core/src/main/java/org/apache/commons/jcs/auxiliary/remote/AbstractRemoteAuxiliaryCache.java
@@ -26,8 +26,8 @@
 import java.util.Set;
 import java.util.concurrent.Callable;
 import java.util.concurrent.ExecutionException;
-import java.util.concurrent.ExecutorService;
 import java.util.concurrent.Future;
+import java.util.concurrent.ThreadPoolExecutor;
 import java.util.concurrent.TimeUnit;
 import java.util.concurrent.TimeoutException;
 
@@ -77,7 +77,7 @@
     private IRemoteCacheAttributes remoteCacheAttributes;
 
     /** A thread pool for gets if configured. */
-    private ExecutorService pool = null;
+    private ThreadPoolExecutor pool = null;
 
     /** Should we get asynchronously using a pool. */
     private boolean usePoolForGet = false;
@@ -113,12 +113,15 @@
 
         if ( getRemoteCacheAttributes().getGetTimeoutMillis() > 0 )
         {
-            pool = ThreadPoolManager.getInstance().getExecutorService( getRemoteCacheAttributes().getThreadPoolName() );
+            pool = ThreadPoolManager.getInstance().getPool( getRemoteCacheAttributes().getThreadPoolName() );
             if ( log.isDebugEnabled() )
             {
                 log.debug( "Thread Pool = " + pool );
             }
-            usePoolForGet = true;
+            if ( pool != null )
+            {
+                usePoolForGet = true;
+            }
         }
     }
 
@@ -142,7 +145,7 @@
                 getRemoteCacheListener().dispose();
             }
         }
-        catch ( IOException ex )
+        catch ( Exception ex )
         {
             log.error( "Couldn't dispose", ex );
             handleException( ex, "Failed to dispose [" + cacheName + "]", ICacheEventLogger.DISPOSE_EVENT );
@@ -570,7 +573,8 @@
 
         if ( pool != null )
         {
-            elems.add(new StatElement<ExecutorService>( "Pool", pool ) );
+            elems.add(new StatElement<Integer>( "Pool Size", Integer.valueOf(pool.getPoolSize()) ) );
+            elems.add(new StatElement<Integer>( "Maximum Pool Size", Integer.valueOf(pool.getMaximumPoolSize()) ) );
         }
 
         if ( getRemoteCacheService() instanceof ZombieCacheServiceNonLocal )
diff --git a/commons-jcs-core/src/main/java/org/apache/commons/jcs/engine/AbstractCacheEventQueue.java b/commons-jcs-core/src/main/java/org/apache/commons/jcs/engine/AbstractCacheEventQueue.java
index 9f37b0c..216a94d 100644
--- a/commons-jcs-core/src/main/java/org/apache/commons/jcs/engine/AbstractCacheEventQueue.java
+++ b/commons-jcs-core/src/main/java/org/apache/commons/jcs/engine/AbstractCacheEventQueue.java
@@ -64,6 +64,9 @@
     /** in milliseconds */
     private int waitBeforeRetry;
 
+    /** this is true if there is any worker thread. */
+    private final AtomicBoolean alive = new AtomicBoolean(false);
+
     /**
      * This means that the queue is functional. If we reached the max number of failures, the queue
      * is marked as non functional and will never work again.
@@ -105,27 +108,21 @@
      * If they queue has an active thread it is considered alive.
      * <p>
      * @return The alive value
-     * 
-     * @deprecated The alive-logic is not used 
      */
-    @Deprecated
-	@Override
+    @Override
     public boolean isAlive()
     {
-        return true;
+        return alive.get();
     }
 
     /**
      * Sets whether the queue is actively processing -- if there are working threads.
      * <p>
      * @param aState
-     * 
-     * @deprecated The alive-logic is not used 
      */
-    @Deprecated
-	public void setAlive( boolean aState )
+    public void setAlive( boolean aState )
     {
-        // do nothing
+        alive.set(aState);
     }
 
     /**
@@ -182,9 +179,17 @@
      * @throws IOException
      */
     @Override
-    public void addPutEvent( ICacheElement<K, V> ce )
+    public synchronized void addPutEvent( ICacheElement<K, V> ce )
+        throws IOException
     {
-        put( new PutEvent( ce ) );
+        if ( isWorking() )
+        {
+            put( new PutEvent( ce ) );
+        }
+        else if ( log.isWarnEnabled() )
+        {
+            log.warn( "Not enqueuing Put Event for [" + this + "] because it's non-functional." );
+        }
     }
 
     /**
@@ -195,28 +200,54 @@
      * @throws IOException
      */
     @Override
-    public void addRemoveEvent( K key )
+    public synchronized void addRemoveEvent( K key )
+        throws IOException
     {
-        put( new RemoveEvent( key ) );
+        if ( isWorking() )
+        {
+            put( new RemoveEvent( key ) );
+        }
+        else if ( log.isWarnEnabled() )
+        {
+            log.warn( "Not enqueuing Remove Event for [" + this + "] because it's non-functional." );
+        }
     }
 
     /**
      * This adds a remove all event to the queue. When it is processed, all elements will be removed
      * from the cache.
+     * <p>
+     * @throws IOException
      */
     @Override
-    public void addRemoveAllEvent()
+    public synchronized void addRemoveAllEvent()
+        throws IOException
     {
-        put( new RemoveAllEvent() );
+        if ( isWorking() )
+        {
+            put( new RemoveAllEvent() );
+        }
+        else if ( log.isWarnEnabled() )
+        {
+            log.warn( "Not enqueuing RemoveAll Event for [" + this + "] because it's non-functional." );
+        }
     }
 
     /**
-     * This adds a dispose event to the queue. When it is processed, the cache is shut down
+     * @throws IOException
      */
     @Override
-    public void addDisposeEvent()
+    public synchronized void addDisposeEvent()
+        throws IOException
     {
-        put( new DisposeEvent() );
+        if ( isWorking() )
+        {
+            put( new DisposeEvent() );
+        }
+        else if ( log.isWarnEnabled() )
+        {
+            log.warn( "Not enqueuing Dispose Event for [" + this + "] because it's non-functional." );
+        }
     }
 
     /**
@@ -262,7 +293,8 @@
                         log.warn( "Error while running event from Queue: " + this
                             + ". Dropping Event and marking Event Queue as non-functional." );
                     }
-                    destroy();
+                    setWorking( false );
+                    setAlive( false );
                     return;
                 }
                 if ( log.isInfoEnabled() )
@@ -280,7 +312,10 @@
                     {
                         log.warn( "Interrupted while sleeping for retry on event " + this + "." );
                     }
-                    destroy();
+                    // TODO consider if this is best. maybe we should just
+                    // destroy
+                    setWorking( false );
+                    setAlive( false );
                 }
             }
         }
@@ -307,8 +342,10 @@
          * Constructor for the PutEvent object.
          * <p>
          * @param ice
+         * @throws IOException
          */
         PutEvent( ICacheElement<K, V> ice )
+            throws IOException
         {
             this.ice = ice;
         }
@@ -354,8 +391,10 @@
          * Constructor for the RemoveEvent object
          * <p>
          * @param key
+         * @throws IOException
          */
         RemoveEvent( K key )
+            throws IOException
         {
             this.key = key;
         }
diff --git a/commons-jcs-core/src/main/java/org/apache/commons/jcs/engine/CacheEventQueue.java b/commons-jcs-core/src/main/java/org/apache/commons/jcs/engine/CacheEventQueue.java
index bf2758f..58fc27b 100644
--- a/commons-jcs-core/src/main/java/org/apache/commons/jcs/engine/CacheEventQueue.java
+++ b/commons-jcs-core/src/main/java/org/apache/commons/jcs/engine/CacheEventQueue.java
@@ -1,5 +1,9 @@
 package org.apache.commons.jcs.engine;
 
+import java.util.ArrayList;
+import java.util.concurrent.LinkedBlockingQueue;
+import java.util.concurrent.TimeUnit;
+
 /*
  * Licensed to the Apache Software Foundation (ASF) under one
  * or more contributor license agreements.  See the NOTICE file
@@ -20,19 +24,35 @@
  */
 
 import org.apache.commons.jcs.engine.behavior.ICacheListener;
-import org.apache.commons.jcs.utils.threadpool.PoolConfiguration;
-import org.apache.commons.jcs.utils.threadpool.PoolConfiguration.WhenBlockedPolicy;
-import org.apache.commons.jcs.utils.threadpool.ThreadPoolManager;
+import org.apache.commons.jcs.engine.stats.StatElement;
+import org.apache.commons.jcs.engine.stats.Stats;
+import org.apache.commons.jcs.engine.stats.behavior.IStatElement;
+import org.apache.commons.jcs.engine.stats.behavior.IStats;
+import org.apache.commons.logging.Log;
+import org.apache.commons.logging.LogFactory;
 
 /**
  * An event queue is used to propagate ordered cache events to one and only one target listener.
+ * <p>
+ * This is a modified version of the experimental version. It should lazy initialize the processor
+ * thread, and kill the thread if the queue goes empty for a specified period, now set to 1 minute.
+ * If something comes in after that a new processor thread should be created.
  */
 public class CacheEventQueue<K, V>
-    extends PooledCacheEventQueue<K, V>
+    extends AbstractCacheEventQueue<K, V>
 {
+    /** The logger. */
+    private static final Log log = LogFactory.getLog( CacheEventQueue.class );
+
     /** The type of queue -- there are pooled and single */
     private static final QueueType queueType = QueueType.SINGLE;
 
+    /** the thread that works the queue. */
+    private Thread processorThread;
+
+    /** Queue implementation */
+    private LinkedBlockingQueue<AbstractCacheEvent> queue = new LinkedBlockingQueue<AbstractCacheEvent>();
+
     /**
      * Constructs with the specified listener and the cache name.
      * <p>
@@ -57,29 +77,7 @@
     public CacheEventQueue( ICacheListener<K, V> listener, long listenerId, String cacheName, int maxFailure,
                             int waitBeforeRetry )
     {
-        super( listener, listenerId, cacheName, maxFailure, waitBeforeRetry, null );
-    }
-
-    /**
-     * Initializes the queue.
-     * <p>
-     * @param listener
-     * @param listenerId
-     * @param cacheName
-     * @param maxFailure
-     * @param waitBeforeRetry
-     * @param threadPoolName
-     */
-    @Override
-    protected void initialize( ICacheListener<K, V> listener, long listenerId, String cacheName, int maxFailure,
-                            int waitBeforeRetry, String threadPoolName )
-    {
-        super.initialize(listener, listenerId, cacheName, maxFailure, waitBeforeRetry);
-
-        // create a default pool with one worker thread to mimic the SINGLE queue behavior
-        pool = ThreadPoolManager.getInstance().createPool(
-        		new PoolConfiguration(false, 0, 1, 0, getWaitToDieMillis(), WhenBlockedPolicy.RUN, 0),
-        		"CacheEventQueue.QProcessor-" + getCacheName());
+        initialize( listener, listenerId, cacheName, maxFailure, waitBeforeRetry );
     }
 
     /**
@@ -92,4 +90,192 @@
     {
         return queueType;
     }
+
+    /**
+     * Kill the processor thread and indicate that the queue is destroyed and no longer alive, but it
+     * can still be working.
+     */
+    protected void stopProcessing()
+    {
+        setAlive(false);
+        processorThread = null;
+    }
+
+    /**
+     * Event Q is empty.
+     * <p>
+     * Calling destroy interrupts the processor thread.
+     */
+    @Override
+    public void destroy()
+    {
+        if ( isAlive() )
+        {
+            setAlive(false);
+
+            if ( log.isInfoEnabled() )
+            {
+                log.info( "Destroying queue, stats =  " + getStatistics() );
+            }
+
+            if ( processorThread != null )
+            {
+                processorThread.interrupt();
+                processorThread = null;
+            }
+
+            if ( log.isInfoEnabled() )
+            {
+                log.info( "Cache event queue destroyed: " + this );
+            }
+        }
+        else
+        {
+            if ( log.isInfoEnabled() )
+            {
+                log.info( "Destroy was called after queue was destroyed. Doing nothing. Stats =  " + getStatistics() );
+            }
+        }
+    }
+
+    /**
+     * Adds an event to the queue.
+     * <p>
+     * @param event
+     */
+    @Override
+    protected void put( AbstractCacheEvent event )
+    {
+        if ( log.isDebugEnabled() )
+        {
+            log.debug( "Event entering Queue for " + getCacheName() + ": " + event );
+        }
+
+        queue.offer(event);
+
+        if ( isWorking() )
+        {
+            if ( !isAlive() )
+            {
+                setAlive(true);
+                processorThread = new QProcessor();
+                processorThread.start();
+                if ( log.isInfoEnabled() )
+                {
+                    log.info( "Cache event queue created: " + this );
+                }
+            }
+        }
+    }
+
+    // /////////////////////////// Inner classes /////////////////////////////
+
+    /**
+     * This is the thread that works the queue.
+     * <p>
+     * @author asmuts
+     * @created January 15, 2002
+     */
+    protected class QProcessor
+        extends Thread
+    {
+        /**
+         * Constructor for the QProcessor object
+         * <p>
+         * @param aQueue the event queue to take items from.
+         */
+        QProcessor()
+        {
+            super( "CacheEventQueue.QProcessor-" + getCacheName() );
+            setDaemon( true );
+        }
+
+        /**
+         * Main processing method for the QProcessor object.
+         * <p>
+         * Waits for a specified time (waitToDieMillis) for something to come in and if no new
+         * events come in during that period the run method can exit and the thread is dereferenced.
+         */
+        @Override
+        public void run()
+        {
+
+            while ( CacheEventQueue.this.isAlive() )
+            {
+                AbstractCacheEvent event = null;
+
+                try
+                {
+                    event = queue.poll(getWaitToDieMillis(), TimeUnit.MILLISECONDS);
+                }
+                catch (InterruptedException e)
+                {
+                    // is ok
+                }
+
+                if ( log.isDebugEnabled() )
+                {
+                    log.debug( "Event from queue = " + event );
+                }
+
+                if ( event == null )
+                {
+                    stopProcessing();
+                }
+
+                if ( event != null && isWorking() && CacheEventQueue.this.isAlive() )
+                {
+                    event.run();
+                }
+            }
+            if ( log.isDebugEnabled() )
+            {
+                log.debug( "QProcessor exiting for " + getCacheName() );
+            }
+        }
+    }
+
+    /**
+     * This method returns semi-structured data on this queue.
+     * <p>
+     * @see org.apache.commons.jcs.engine.behavior.ICacheEventQueue#getStatistics()
+     * @return information on the status and history of the queue
+     */
+    @Override
+    public IStats getStatistics()
+    {
+        IStats stats = new Stats();
+        stats.setTypeName( "Cache Event Queue" );
+
+        ArrayList<IStatElement<?>> elems = new ArrayList<IStatElement<?>>();
+
+        elems.add(new StatElement<Boolean>( "Working", Boolean.valueOf(this.isWorking()) ) );
+        elems.add(new StatElement<Boolean>( "Alive", Boolean.valueOf(this.isAlive()) ) );
+        elems.add(new StatElement<Boolean>( "Empty", Boolean.valueOf(this.isEmpty()) ) );
+        elems.add(new StatElement<Integer>( "Size", Integer.valueOf(this.size()) ) );
+
+        stats.setStatElements( elems );
+
+        return stats;
+    }
+
+    /**
+     * @return whether there are any items in the queue.
+     */
+    @Override
+    public boolean isEmpty()
+    {
+        return queue.isEmpty();
+    }
+
+    /**
+     * Returns the number of elements in the queue.
+     * <p>
+     * @return number of items in the queue.
+     */
+    @Override
+    public int size()
+    {
+        return queue.size();
+    }
 }
diff --git a/commons-jcs-core/src/main/java/org/apache/commons/jcs/engine/PooledCacheEventQueue.java b/commons-jcs-core/src/main/java/org/apache/commons/jcs/engine/PooledCacheEventQueue.java
index e4b1089..81dfe23 100644
--- a/commons-jcs-core/src/main/java/org/apache/commons/jcs/engine/PooledCacheEventQueue.java
+++ b/commons-jcs-core/src/main/java/org/apache/commons/jcs/engine/PooledCacheEventQueue.java
@@ -2,7 +2,6 @@
 
 import java.util.ArrayList;
 import java.util.concurrent.BlockingQueue;
-import java.util.concurrent.ExecutorService;
 import java.util.concurrent.ThreadPoolExecutor;
 
 /*
@@ -53,10 +52,7 @@
     private static final QueueType queueType = QueueType.POOLED;
 
     /** The Thread Pool to execute events with. */
-    protected ExecutorService pool = null;
-
-    /** The Thread Pool queue */
-    protected BlockingQueue<Runnable> queue = null;
+    private ThreadPoolExecutor pool = null;
 
     /**
      * Constructor for the CacheEventQueue object
@@ -90,13 +86,8 @@
         super.initialize(listener, listenerId, cacheName, maxFailure, waitBeforeRetry);
 
         // this will share the same pool with other event queues by default.
-        pool = ThreadPoolManager.getInstance().getExecutorService(
+        pool = ThreadPoolManager.getInstance().getPool(
                 (threadPoolName == null) ? "cache_event_queue" : threadPoolName );
-        
-        if (pool instanceof ThreadPoolExecutor)
-        {
-        	queue = ((ThreadPoolExecutor) pool).getQueue();
-        }
     }
 
     /**
@@ -114,9 +105,9 @@
     @Override
     public synchronized void destroy()
     {
-        if ( isWorking() )
+        if ( isAlive() )
         {
-            setWorking(false);
+            setAlive(false);
             pool.shutdownNow();
             if ( log.isInfoEnabled() )
             {
@@ -147,15 +138,20 @@
 
         ArrayList<IStatElement<?>> elems = new ArrayList<IStatElement<?>>();
 
-        elems.add(new StatElement<Boolean>( "Working", Boolean.valueOf(isWorking()) ) );
+        elems.add(new StatElement<Boolean>( "Working", Boolean.valueOf(super.isWorking()) ) );
+        elems.add(new StatElement<Boolean>( "Alive", Boolean.valueOf(this.isAlive()) ) );
         elems.add(new StatElement<Boolean>( "Empty", Boolean.valueOf(this.isEmpty()) ) );
 
-        if ( queue != null )
+        if ( pool.getQueue() != null )
         {
-            elems.add(new StatElement<Integer>( "Queue Size", Integer.valueOf(queue.size()) ) );
-            elems.add(new StatElement<Integer>( "Queue Capacity", Integer.valueOf(queue.remainingCapacity()) ) );
+            BlockingQueue<Runnable> bb = pool.getQueue();
+            elems.add(new StatElement<Integer>( "Queue Size", Integer.valueOf(bb.size()) ) );
+            elems.add(new StatElement<Integer>( "Queue Capacity", Integer.valueOf(bb.remainingCapacity()) ) );
         }
 
+        elems.add(new StatElement<Integer>( "Pool Size", Integer.valueOf(pool.getPoolSize()) ) );
+        elems.add(new StatElement<Integer>( "Maximum Pool Size", Integer.valueOf(pool.getMaximumPoolSize()) ) );
+
         stats.setStatElements( elems );
 
         return stats;
@@ -170,25 +166,32 @@
     @Override
     public boolean isEmpty()
     {
-        return size() == 0;
+        if ( pool.getQueue() == null )
+        {
+            return true;
+        }
+        else
+        {
+            return pool.getQueue().size() == 0;
+        }
     }
 
     /**
      * Returns the number of elements in the queue. If the queue cannot determine the size
-     * accurately it will return 0.
+     * accurately it will return 1.
      * <p>
      * @return number of items in the queue.
      */
     @Override
     public int size()
     {
-        if ( queue == null )
+        if ( pool.getQueue() == null )
         {
             return 0;
         }
         else
         {
-            return queue.size();
+            return pool.getQueue().size();
         }
     }
 }
diff --git a/commons-jcs-core/src/main/java/org/apache/commons/jcs/engine/control/event/ElementEventQueue.java b/commons-jcs-core/src/main/java/org/apache/commons/jcs/engine/control/event/ElementEventQueue.java
index 44ab573..1a6e9bd 100644
--- a/commons-jcs-core/src/main/java/org/apache/commons/jcs/engine/control/event/ElementEventQueue.java
+++ b/commons-jcs-core/src/main/java/org/apache/commons/jcs/engine/control/event/ElementEventQueue.java
@@ -20,14 +20,14 @@
  */
 
 import java.io.IOException;
-import java.util.concurrent.ExecutorService;
+import java.util.concurrent.LinkedBlockingQueue;
+import java.util.concurrent.ThreadPoolExecutor;
+import java.util.concurrent.TimeUnit;
 
 import org.apache.commons.jcs.engine.control.event.behavior.IElementEvent;
 import org.apache.commons.jcs.engine.control.event.behavior.IElementEventHandler;
 import org.apache.commons.jcs.engine.control.event.behavior.IElementEventQueue;
-import org.apache.commons.jcs.utils.threadpool.PoolConfiguration;
-import org.apache.commons.jcs.utils.threadpool.PoolConfiguration.WhenBlockedPolicy;
-import org.apache.commons.jcs.utils.threadpool.ThreadPoolManager;
+import org.apache.commons.jcs.utils.threadpool.DaemonThreadFactory;
 import org.apache.commons.logging.Log;
 import org.apache.commons.logging.LogFactory;
 
@@ -45,16 +45,20 @@
     /** shutdown or not */
     private boolean destroyed = false;
 
+    /** The event queue */
+    private LinkedBlockingQueue<Runnable> queue;
+
     /** The worker thread pool. */
-    private ExecutorService queueProcessor;
+    private ThreadPoolExecutor queueProcessor;
 
     /**
      * Constructor for the ElementEventQueue object
      */
     public ElementEventQueue()
     {
-        queueProcessor = ThreadPoolManager.getInstance().createPool(
-        		new PoolConfiguration(false, 0, 1, 1, 0, WhenBlockedPolicy.RUN, 1), THREAD_PREFIX);
+        queue = new LinkedBlockingQueue<Runnable>();
+        queueProcessor = new ThreadPoolExecutor(1, 1, 0L, TimeUnit.MILLISECONDS,
+                queue, new DaemonThreadFactory(THREAD_PREFIX));
 
         if ( log.isDebugEnabled() )
         {
diff --git a/commons-jcs-core/src/main/java/org/apache/commons/jcs/engine/memory/AbstractDoubleLinkedListMemoryCache.java b/commons-jcs-core/src/main/java/org/apache/commons/jcs/engine/memory/AbstractDoubleLinkedListMemoryCache.java
index 5f85104..b5523d7 100644
--- a/commons-jcs-core/src/main/java/org/apache/commons/jcs/engine/memory/AbstractDoubleLinkedListMemoryCache.java
+++ b/commons-jcs-core/src/main/java/org/apache/commons/jcs/engine/memory/AbstractDoubleLinkedListMemoryCache.java
@@ -20,10 +20,15 @@
  */
 
 import java.io.IOException;
+import java.util.Iterator;
+import java.util.LinkedHashSet;
 import java.util.List;
+import java.util.Map;
+import java.util.Set;
 import java.util.concurrent.ConcurrentHashMap;
 import java.util.concurrent.ConcurrentMap;
 
+import org.apache.commons.jcs.engine.CacheConstants;
 import org.apache.commons.jcs.engine.behavior.ICacheElement;
 import org.apache.commons.jcs.engine.control.CompositeCache;
 import org.apache.commons.jcs.engine.control.group.GroupAttrName;
@@ -194,6 +199,74 @@
     }
 
     /**
+     * Get an item from the cache If the item is found, it is removed from the list and added first.
+     * <p>
+     *
+     * @param key
+     *            Identifies item to find
+     * @return ICacheElement&lt;K, V&gt; if found, else null
+     * @throws IOException
+     */
+    @Override
+    public final ICacheElement<K, V> get(K key) throws IOException
+    {
+        ICacheElement<K, V> ce = null;
+
+        if (log.isDebugEnabled())
+        {
+            log.debug(getCacheName() + ": getting item for key " + key);
+        }
+
+        MemoryElementDescriptor<K, V> me = map.get(key);
+
+        if (me != null)
+        {
+            hitCnt.incrementAndGet();
+
+            lock.lock();
+            try
+            {
+                ce = me.getCacheElement();
+                // ABSTRACT
+                adjustListForGet(me);
+            }
+            finally
+            {
+                lock.unlock();
+            }
+
+            if (log.isDebugEnabled())
+            {
+                log.debug(getCacheName() + ": LRUMemoryCache hit for " + key);
+            }
+        }
+        else
+        {
+            missCnt.incrementAndGet();
+
+            if (log.isDebugEnabled())
+            {
+                log.debug(getCacheName() + ": LRUMemoryCache miss for " + key);
+            }
+        }
+
+        if (log.isDebugEnabled())
+        {
+            verifyCache();
+        }
+
+        return ce;
+    }
+
+    /**
+     * Adjust the list as needed for a get. This allows children to control the algorithm
+     * <p>
+     *
+     * @param me
+     */
+    protected abstract void adjustListForGet(MemoryElementDescriptor<K, V> me);
+
+    /**
      * This instructs the memory cache to remove the <i>numberToFree</i> according to its eviction
      * policy. For example, the LRUMemoryCache will remove the <i>numberToFree</i> least recently
      * used items. These will be spooled to disk if a disk auxiliary is available.
@@ -270,61 +343,116 @@
     }
 
     /**
-     * @see org.apache.commons.jcs.engine.memory.AbstractMemoryCache#get(java.lang.Object)
-     */
-    @Override
-    public ICacheElement<K, V> get(K key) throws IOException
-    {
-        ICacheElement<K, V> ce = super.get(key);
-
-        if (log.isDebugEnabled())
-        {
-            verifyCache();
-        }
-
-        return ce;
-    }
-
-    /**
-     * Adjust the list as needed for a get. This allows children to control the algorithm
+     * Removes an item from the cache. This method handles hierarchical removal. If the key is a
+     * String and ends with the CacheConstants.NAME_COMPONENT_DELIMITER, then all items with keys
+     * starting with the argument String will be removed.
      * <p>
      *
-     * @param me
-     */
-    protected abstract void adjustListForGet(MemoryElementDescriptor<K, V> me);
-
-    /**
-     * Update control structures after get
-     * (guarded by the lock)
-     *
-     * @param me the memory element descriptor
+     * @param key
+     * @return true if the removal was successful
+     * @throws IOException
      */
     @Override
-    protected void lockedGetElement(MemoryElementDescriptor<K, V> me)
+    public boolean remove(K key) throws IOException
     {
-        adjustListForGet(me);
+        if (log.isDebugEnabled())
+        {
+            log.debug("removing item for key: " + key);
+        }
+
+        boolean removed = false;
+
+        // handle partial removal
+        if (key instanceof String && ((String) key).endsWith(CacheConstants.NAME_COMPONENT_DELIMITER))
+        {
+            // remove all keys of the same name hierarchy.
+            for (Iterator<Map.Entry<K, MemoryElementDescriptor<K, V>>> itr = map.entrySet().iterator(); itr.hasNext();)
+            {
+                Map.Entry<K, MemoryElementDescriptor<K, V>> entry = itr.next();
+                K k = entry.getKey();
+
+                if (k instanceof String && ((String) k).startsWith(key.toString()))
+                {
+                    lock.lock();
+                    try
+                    {
+                        list.remove(entry.getValue());
+                        itr.remove();
+                        removed = true;
+                    }
+                    finally
+                    {
+                        lock.unlock();
+                    }
+                }
+            }
+        }
+        else if (key instanceof GroupAttrName && ((GroupAttrName<?>) key).attrName == null)
+        {
+            // remove all keys of the same name hierarchy.
+            for (Iterator<Map.Entry<K, MemoryElementDescriptor<K, V>>> itr = map.entrySet().iterator(); itr.hasNext();)
+            {
+                Map.Entry<K, MemoryElementDescriptor<K, V>> entry = itr.next();
+                K k = entry.getKey();
+
+                if (k instanceof GroupAttrName && ((GroupAttrName<?>) k).groupId.equals(((GroupAttrName<?>) key).groupId))
+                {
+                    lock.lock();
+                    try
+                    {
+                        list.remove(entry.getValue());
+                        itr.remove();
+                        removed = true;
+                    }
+                    finally
+                    {
+                        lock.unlock();
+                    }
+                }
+            }
+        }
+        else
+        {
+            // remove single item.
+            lock.lock();
+            try
+            {
+                MemoryElementDescriptor<K, V> me = map.remove(key);
+                if (me != null)
+                {
+                    list.remove(me);
+                    removed = true;
+                }
+            }
+            finally
+            {
+                lock.unlock();
+            }
+        }
+
+        return removed;
     }
 
     /**
-     * Remove element from control structure
-     * (guarded by the lock)
+     * Remove all of the elements from both the Map and the linked list implementation. Overrides
+     * base class.
+     * <p>
      *
-     * @param me the memory element descriptor
+     * @throws IOException
      */
     @Override
-    protected void lockedRemoveElement(MemoryElementDescriptor<K, V> me)
+    public void removeAll() throws IOException
     {
-        list.remove(me);
-    }
-
-    /**
-     * Removes all cached items from the cache control structures.
-     * (guarded by the lock)
-     */
-    @Override
-    protected void lockedRemoveAll()
-    {
-        list.removeAll();
+        lock.lock();
+        try
+        {
+            list.removeAll();
+            map.clear();
+        }
+        finally
+        {
+            lock.unlock();
+        }
     }
 
     // --------------------------- internal methods (linked list implementation)
@@ -503,6 +631,17 @@
     }
 
     /**
+     * Get an Array of the keys for all elements in the memory cache
+     *
+     * @return An Object[]
+     */
+    @Override
+    public Set<K> getKeySet()
+    {
+        return new LinkedHashSet<K>(map.keySet());
+    }
+
+    /**
      * This returns semi-structured information on the memory cache, such as the size, put count,
      * hit count, and miss count.
      * <p>
diff --git a/commons-jcs-core/src/main/java/org/apache/commons/jcs/engine/memory/AbstractMemoryCache.java b/commons-jcs-core/src/main/java/org/apache/commons/jcs/engine/memory/AbstractMemoryCache.java
index dc4bf5c..87929fa 100644
--- a/commons-jcs-core/src/main/java/org/apache/commons/jcs/engine/memory/AbstractMemoryCache.java
+++ b/commons-jcs-core/src/main/java/org/apache/commons/jcs/engine/memory/AbstractMemoryCache.java
@@ -22,19 +22,16 @@
 import java.io.IOException;
 import java.util.ArrayList;
 import java.util.HashMap;
-import java.util.Iterator;
-import java.util.LinkedHashSet;
 import java.util.Map;
 import java.util.Set;
 import java.util.concurrent.atomic.AtomicLong;
 import java.util.concurrent.locks.Lock;
 import java.util.concurrent.locks.ReentrantLock;
 
-import org.apache.commons.jcs.engine.CacheConstants;
+import org.apache.commons.jcs.engine.CacheStatus;
 import org.apache.commons.jcs.engine.behavior.ICacheElement;
 import org.apache.commons.jcs.engine.behavior.ICompositeCacheAttributes;
 import org.apache.commons.jcs.engine.control.CompositeCache;
-import org.apache.commons.jcs.engine.control.group.GroupAttrName;
 import org.apache.commons.jcs.engine.memory.behavior.IMemoryCache;
 import org.apache.commons.jcs.engine.memory.util.MemoryElementDescriptor;
 import org.apache.commons.jcs.engine.stats.StatElement;
@@ -46,6 +43,9 @@
 
 /**
  * This base includes some common code for memory caches.
+ * <p>
+ * This keeps a static reference to a memory shrinker clock daemon. If this region is configured to
+ * use the shrinker, the clock daemon will be setup to run the shrinker on this region.
  */
 public abstract class AbstractMemoryCache<K, V>
     implements IMemoryCache<K, V>
@@ -59,6 +59,9 @@
     /** The cache region this store is associated with */
     private CompositeCache<K, V> cache;
 
+    /** status */
+    private CacheStatus status;
+
     /** How many to spool at a time. */
     protected int chunkSize;
 
@@ -93,6 +96,8 @@
         this.cache = hub;
 
         this.map = createMap();
+
+        this.status = CacheStatus.ALIVE;
     }
 
     /**
@@ -104,6 +109,28 @@
     public abstract Map<K, MemoryElementDescriptor<K, V>> createMap();
 
     /**
+     * Removes an item from the cache
+     * <p>
+     * @param key Identifies item to be removed
+     * @return Description of the Return Value
+     * @throws IOException Description of the Exception
+     */
+    @Override
+    public abstract boolean remove( K key )
+        throws IOException;
+
+    /**
+     * Get an item from the cache
+     * <p>
+     * @param key Description of the Parameter
+     * @return Description of the Return Value
+     * @throws IOException Description of the Exception
+     */
+    @Override
+    public abstract ICacheElement<K, V> get( K key )
+        throws IOException;
+
+    /**
      * Gets multiple items from the cache based on the given set of keys.
      * <p>
      * @param keys
@@ -176,32 +203,26 @@
         throws IOException;
 
     /**
+     * Get a set of the keys for all elements in the memory cache
+     * <p>
+     * @return A set of the key type
+     */
+    @Override
+    public abstract Set<K> getKeySet();
+
+    /**
      * Removes all cached items from the cache.
      * <p>
      * @throws IOException
      */
     @Override
-    public void removeAll() throws IOException
+    public void removeAll()
+        throws IOException
     {
-        lock.lock();
-        try
-        {
-            lockedRemoveAll();
-            map.clear();
-        }
-        finally
-        {
-            lock.unlock();
-        }
+        map.clear();
     }
 
     /**
-     * Removes all cached items from the cache control structures.
-     * (guarded by the lock)
-     */
-    protected abstract void lockedRemoveAll();
-
-    /**
      * Prepares for shutdown. Reset statistics
      * <p>
      * @throws IOException
@@ -249,6 +270,16 @@
     }
 
     /**
+     * Returns the cache status.
+     * <p>
+     * @return The status value
+     */
+    public CacheStatus getStatus()
+    {
+        return this.status;
+    }
+
+    /**
      * Returns the cache (aka "region") name.
      * <p>
      * @return The cacheName value
@@ -320,204 +351,4 @@
     {
         return this.cache;
     }
-
-    /**
-     * Remove all keys of the same group hierarchy.
-     * @param key the key
-     * @return true if something has been removed
-     */
-    protected boolean removeByGroup(K key)
-    {
-        boolean removed = false;
-
-        // remove all keys of the same group hierarchy.
-        for (Iterator<Map.Entry<K, MemoryElementDescriptor<K, V>>> itr = map.entrySet().iterator(); itr.hasNext();)
-        {
-            Map.Entry<K, MemoryElementDescriptor<K, V>> entry = itr.next();
-            K k = entry.getKey();
-
-            if (k instanceof GroupAttrName && ((GroupAttrName<?>) k).groupId.equals(((GroupAttrName<?>) key).groupId))
-            {
-                lock.lock();
-                try
-                {
-                    itr.remove();
-                    lockedRemoveElement(entry.getValue());
-                    removed = true;
-                }
-                finally
-                {
-                    lock.unlock();
-                }
-            }
-        }
-
-        return removed;
-    }
-
-    /**
-     * Remove all keys of the same name hierarchy.
-     *
-     * @param key the key
-     * @return true if something has been removed
-     */
-    protected boolean removeByHierarchy(K key)
-    {
-        boolean removed = false;
-
-        // remove all keys of the same name hierarchy.
-        for (Iterator<Map.Entry<K, MemoryElementDescriptor<K, V>>> itr = map.entrySet().iterator(); itr.hasNext();)
-        {
-            Map.Entry<K, MemoryElementDescriptor<K, V>> entry = itr.next();
-            K k = entry.getKey();
-
-            if (k instanceof String && ((String) k).startsWith(key.toString()))
-            {
-                lock.lock();
-                try
-                {
-                    itr.remove();
-                    lockedRemoveElement(entry.getValue());
-                    removed = true;
-                }
-                finally
-                {
-                    lock.unlock();
-                }
-            }
-        }
-
-        return removed;
-    }
-
-    /**
-     * Remove element from control structure
-     * (guarded by the lock)
-     *
-     * @param me the memory element descriptor
-     */
-    protected abstract void lockedRemoveElement(MemoryElementDescriptor<K, V> me);
-
-    /**
-     * Removes an item from the cache. This method handles hierarchical removal. If the key is a
-     * String and ends with the CacheConstants.NAME_COMPONENT_DELIMITER, then all items with keys
-     * starting with the argument String will be removed.
-     * <p>
-     *
-     * @param key
-     * @return true if the removal was successful
-     * @throws IOException
-     */
-    @Override
-    public boolean remove(K key) throws IOException
-    {
-        if (log.isDebugEnabled())
-        {
-            log.debug("removing item for key: " + key);
-        }
-
-        boolean removed = false;
-
-        // handle partial removal
-        if (key instanceof String && ((String) key).endsWith(CacheConstants.NAME_COMPONENT_DELIMITER))
-        {
-            removed = removeByHierarchy(key);
-        }
-        else if (key instanceof GroupAttrName && ((GroupAttrName<?>) key).attrName == null)
-        {
-            removed = removeByGroup(key);
-        }
-        else
-        {
-            // remove single item.
-            lock.lock();
-            try
-            {
-                MemoryElementDescriptor<K, V> me = map.remove(key);
-                if (me != null)
-                {
-                    lockedRemoveElement(me);
-                    removed = true;
-                }
-            }
-            finally
-            {
-                lock.unlock();
-            }
-        }
-
-        return removed;
-    }
-
-    /**
-     * Get an Array of the keys for all elements in the memory cache
-     *
-     * @return An Object[]
-     */
-    @Override
-    public Set<K> getKeySet()
-    {
-        return new LinkedHashSet<K>(map.keySet());
-    }
-
-    /**
-     * Get an item from the cache.
-     * <p>
-     *
-     * @param key Identifies item to find
-     * @return ICacheElement&lt;K, V&gt; if found, else null
-     * @throws IOException
-     */
-    @Override
-    public ICacheElement<K, V> get(K key) throws IOException
-    {
-        ICacheElement<K, V> ce = null;
-
-        if (log.isDebugEnabled())
-        {
-            log.debug(getCacheName() + ": getting item for key " + key);
-        }
-
-        MemoryElementDescriptor<K, V> me = map.get(key);
-
-        if (me != null)
-        {
-            hitCnt.incrementAndGet();
-            ce = me.getCacheElement();
-
-            lock.lock();
-            try
-            {
-                lockedGetElement(me);
-            }
-            finally
-            {
-                lock.unlock();
-            }
-
-            if (log.isDebugEnabled())
-            {
-                log.debug(getCacheName() + ": MemoryCache hit for " + key);
-            }
-        }
-        else
-        {
-            missCnt.incrementAndGet();
-
-            if (log.isDebugEnabled())
-            {
-                log.debug(getCacheName() + ": MemoryCache miss for " + key);
-            }
-        }
-
-        return ce;
-    }
-
-    /**
-     * Update control structures after get
-     * (guarded by the lock)
-     *
-     * @param me the memory element descriptor
-     */
-    protected abstract void lockedGetElement(MemoryElementDescriptor<K, V> me);
 }
diff --git a/commons-jcs-core/src/main/java/org/apache/commons/jcs/engine/memory/lru/LHMLRUMemoryCache.java b/commons-jcs-core/src/main/java/org/apache/commons/jcs/engine/memory/lru/LHMLRUMemoryCache.java
index 2679fb7..b6ff779 100644
--- a/commons-jcs-core/src/main/java/org/apache/commons/jcs/engine/memory/lru/LHMLRUMemoryCache.java
+++ b/commons-jcs-core/src/main/java/org/apache/commons/jcs/engine/memory/lru/LHMLRUMemoryCache.java
@@ -21,10 +21,15 @@
 
 import java.io.IOException;
 import java.util.Collections;
+import java.util.Iterator;
+import java.util.LinkedHashSet;
 import java.util.Map;
+import java.util.Set;
 
+import org.apache.commons.jcs.engine.CacheConstants;
 import org.apache.commons.jcs.engine.behavior.ICacheElement;
 import org.apache.commons.jcs.engine.control.CompositeCache;
+import org.apache.commons.jcs.engine.control.group.GroupAttrName;
 import org.apache.commons.jcs.engine.memory.AbstractMemoryCache;
 import org.apache.commons.jcs.engine.memory.util.MemoryElementDescriptor;
 import org.apache.commons.jcs.engine.stats.behavior.IStats;
@@ -78,37 +83,124 @@
     }
 
     /**
-     * Update control structures after get
-     * (guarded by the lock)
-     *
-     * @param me the memory element descriptor
+     * Get an item from the cache
+     * <p>
+     * @param key Identifies item to find
+     * @return ICacheElement&lt;K, V&gt; if found, else null
+     * @throws IOException
      */
     @Override
-    protected void lockedGetElement(MemoryElementDescriptor<K, V> me)
+    public ICacheElement<K, V> get( K key )
+        throws IOException
     {
-        // empty
+        if ( log.isDebugEnabled() )
+        {
+            log.debug( "getting item from cache " + getCacheName() + " for key " + key );
+        }
+
+        MemoryElementDescriptor<K, V> me = map.get( key );
+
+        if ( me != null )
+        {
+            hitCnt.incrementAndGet();
+            if ( log.isDebugEnabled() )
+            {
+                log.debug( getCacheName() + ": LHMLRUMemoryCache hit for " + key );
+            }
+            return me.getCacheElement();
+        }
+        else
+        {
+            missCnt.incrementAndGet();
+            if ( log.isDebugEnabled() )
+            {
+                log.debug( getCacheName() + ": LHMLRUMemoryCache miss for " + key );
+            }
+        }
+
+        return null;
     }
 
     /**
-     * Remove element from control structure
-     * (guarded by the lock)
-     *
-     * @param me the memory element descriptor
+     * Removes an item from the cache. This method handles hierarchical removal. If the key is a
+     * String and ends with the CacheConstants.NAME_COMPONENT_DELIMITER, then all items with keys
+     * starting with the argument String will be removed.
+     * <p>
+     * @param key
+     * @return true if removed
+     * @throws IOException
      */
     @Override
-    protected void lockedRemoveElement(MemoryElementDescriptor<K, V> me)
+    public boolean remove( K key )
+        throws IOException
     {
-        // empty
+        if ( log.isDebugEnabled() )
+        {
+            log.debug( "removing item for key: " + key );
+        }
+
+        boolean removed = false;
+
+        // handle partial removal
+        if ( key instanceof String && ( (String) key ).endsWith( CacheConstants.NAME_COMPONENT_DELIMITER ) )
+        {
+            // remove all keys of the same name hierarchy.
+            synchronized ( map )
+            {
+                for (Iterator<Map.Entry<K, MemoryElementDescriptor<K, V>>> itr = map.entrySet().iterator(); itr.hasNext(); )
+                {
+                    Map.Entry<K, MemoryElementDescriptor<K, V>> entry = itr.next();
+                    K k = entry.getKey();
+
+                    if ( k instanceof String && ( (String) k ).startsWith( key.toString() ) )
+                    {
+                        itr.remove();
+                        removed = true;
+                    }
+                }
+            }
+        }
+        else if ( key instanceof GroupAttrName && ((GroupAttrName<?>)key).attrName == null )
+        {
+            // remove all keys of the same name hierarchy.
+            synchronized ( map )
+            {
+                for (Iterator<Map.Entry<K, MemoryElementDescriptor<K, V>>> itr = map.entrySet().iterator(); itr.hasNext(); )
+                {
+                    Map.Entry<K, MemoryElementDescriptor<K, V>> entry = itr.next();
+                    K k = entry.getKey();
+
+                    if ( k instanceof GroupAttrName &&
+                        ((GroupAttrName<?>)k).groupId.equals(((GroupAttrName<?>)key).groupId) )
+                    {
+                        itr.remove();
+                        removed = true;
+                    }
+                }
+            }
+        }
+        else
+        {
+            // remove single item.
+            MemoryElementDescriptor<K, V> me = map.remove( key );
+            if ( me != null )
+            {
+                removed = true;
+            }
+        }
+
+        return removed;
     }
 
     /**
-     * Removes all cached items from the cache control structures.
-     * (guarded by the lock)
+     * Get an Array of the keys for all elements in the memory cache
+     * <p>
+     * @return An Object[]
      */
     @Override
-    protected void lockedRemoveAll()
+    public Set<K> getKeySet()
     {
-        // empty
+        return new LinkedHashSet<K>(map.keySet());
     }
 
     /**
diff --git a/commons-jcs-core/src/main/java/org/apache/commons/jcs/engine/memory/soft/SoftReferenceMemoryCache.java b/commons-jcs-core/src/main/java/org/apache/commons/jcs/engine/memory/soft/SoftReferenceMemoryCache.java
index b5c703b..5108c66 100644
--- a/commons-jcs-core/src/main/java/org/apache/commons/jcs/engine/memory/soft/SoftReferenceMemoryCache.java
+++ b/commons-jcs-core/src/main/java/org/apache/commons/jcs/engine/memory/soft/SoftReferenceMemoryCache.java
@@ -22,6 +22,7 @@
 import java.io.IOException;
 import java.lang.ref.SoftReference;
 import java.util.HashSet;
+import java.util.Iterator;
 import java.util.List;
 import java.util.Map;
 import java.util.Set;
@@ -29,9 +30,11 @@
 import java.util.concurrent.ConcurrentMap;
 import java.util.concurrent.LinkedBlockingQueue;
 
+import org.apache.commons.jcs.engine.CacheConstants;
 import org.apache.commons.jcs.engine.behavior.ICacheElement;
 import org.apache.commons.jcs.engine.behavior.ICompositeCacheAttributes;
 import org.apache.commons.jcs.engine.control.CompositeCache;
+import org.apache.commons.jcs.engine.control.group.GroupAttrName;
 import org.apache.commons.jcs.engine.memory.AbstractMemoryCache;
 import org.apache.commons.jcs.engine.memory.util.MemoryElementDescriptor;
 import org.apache.commons.jcs.engine.memory.util.SoftReferenceElementDescriptor;
@@ -144,41 +147,107 @@
     }
 
     /**
-     * Update control structures after get
-     * (guarded by the lock)
+     * Removes an item from the cache. This method handles hierarchical removal. If the key is a
+     * String and ends with the CacheConstants.NAME_COMPONENT_DELIMITER, then all items with keys
+     * starting with the argument String will be removed.
+     * <p>
      *
-     * @param me the memory element descriptor
+     * @param key
+     * @return true if the removal was successful
+     * @throws IOException
      */
     @Override
-    protected void lockedGetElement(MemoryElementDescriptor<K, V> me)
+    public boolean remove(K key) throws IOException
     {
-        ICacheElement<K, V> val = me.getCacheElement();
-        val.getElementAttributes().setLastAccessTimeNow();
+        if (log.isDebugEnabled())
+        {
+            log.debug("removing item for key: " + key);
+        }
 
-        // update the ordering of the strong references
-        strongReferences.add(val);
-        trimStrongReferences();
+        boolean removed = false;
+
+        // handle partial removal
+        if (key instanceof String && ((String) key).endsWith(CacheConstants.NAME_COMPONENT_DELIMITER))
+        {
+            // remove all keys of the same name hierarchy.
+            for (Iterator<Map.Entry<K, MemoryElementDescriptor<K, V>>> itr = map.entrySet().iterator();
+                    itr.hasNext();)
+            {
+                Map.Entry<K, MemoryElementDescriptor<K, V>> entry = itr.next();
+                K k = entry.getKey();
+
+                if (k instanceof String && ((String) k).startsWith(key.toString()))
+                {
+                    lock.lock();
+                    try
+                    {
+                        strongReferences.remove(entry.getValue().getCacheElement());
+                        itr.remove();
+                        removed = true;
+                    }
+                    finally
+                    {
+                        lock.unlock();
+                    }
+                }
+            }
+        }
+        else if (key instanceof GroupAttrName && ((GroupAttrName<?>) key).attrName == null)
+        {
+            // remove all keys of the same name hierarchy.
+            for (Iterator<Map.Entry<K, MemoryElementDescriptor<K, V>>> itr = map.entrySet().iterator();
+                    itr.hasNext();)
+            {
+                Map.Entry<K, MemoryElementDescriptor<K, V>> entry = itr.next();
+                K k = entry.getKey();
+
+                if (k instanceof GroupAttrName && ((GroupAttrName<?>) k).groupId.equals(((GroupAttrName<?>) key).groupId))
+                {
+                    lock.lock();
+                    try
+                    {
+                        strongReferences.remove(entry.getValue().getCacheElement());
+                        itr.remove();
+                        removed = true;
+                    }
+                    finally
+                    {
+                        lock.unlock();
+                    }
+                }
+            }
+        }
+        else
+        {
+            // remove single item.
+            lock.lock();
+            try
+            {
+                MemoryElementDescriptor<K, V> me = map.remove(key);
+                if (me != null)
+                {
+                    strongReferences.remove(me.getCacheElement());
+                    removed = true;
+                }
+            }
+            finally
+            {
+                lock.unlock();
+            }
+        }
+
+        return removed;
     }
 
     /**
-     * Remove element from control structure
-     * (guarded by the lock)
-     *
-     * @param me the memory element descriptor
+     * Removes all cached items from the cache.
+     * <p>
+     * @throws IOException
      */
     @Override
-    protected void lockedRemoveElement(MemoryElementDescriptor<K, V> me)
+    public void removeAll() throws IOException
     {
-        strongReferences.remove(me.getCacheElement());
-    }
-
-    /**
-     * Removes all cached items from the cache control structures.
-     * (guarded by the lock)
-     */
-    @Override
-    protected void lockedRemoveAll()
-    {
+        super.removeAll();
         strongReferences.clear();
     }
 
@@ -225,6 +294,48 @@
     }
 
     /**
+     * Get an item from the cache
+     * <p>
+     * @param key Description of the Parameter
+     * @return Description of the Return Value
+     * @throws IOException Description of the Exception
+     */
+    @Override
+    public ICacheElement<K, V> get(K key) throws IOException
+    {
+        ICacheElement<K, V> val = null;
+        lock.lock();
+
+        try
+        {
+            val = getQuiet(key);
+            if (val != null)
+            {
+                val.getElementAttributes().setLastAccessTimeNow();
+
+                // update the ordering of the strong references
+                strongReferences.add(val);
+                trimStrongReferences();
+            }
+        }
+        finally
+        {
+            lock.unlock();
+        }
+
+        if (val == null)
+        {
+            missCnt.incrementAndGet();
+        }
+        else
+        {
+            hitCnt.incrementAndGet();
+        }
+
+        return val;
+    }
+
+    /**
      * This can't be implemented.
      * <p>
      * @param numberToFree
diff --git a/commons-jcs-core/src/main/java/org/apache/commons/jcs/utils/discovery/UDPDiscoveryReceiver.java b/commons-jcs-core/src/main/java/org/apache/commons/jcs/utils/discovery/UDPDiscoveryReceiver.java
index 07a6687..e8f9cba 100644
--- a/commons-jcs-core/src/main/java/org/apache/commons/jcs/utils/discovery/UDPDiscoveryReceiver.java
+++ b/commons-jcs-core/src/main/java/org/apache/commons/jcs/utils/discovery/UDPDiscoveryReceiver.java
@@ -25,15 +25,14 @@
 import java.net.DatagramPacket;
 import java.net.InetAddress;
 import java.net.MulticastSocket;
-import java.util.concurrent.ExecutorService;
+import java.util.concurrent.Executors;
+import java.util.concurrent.ThreadPoolExecutor;
 
 import org.apache.commons.jcs.engine.CacheInfo;
 import org.apache.commons.jcs.engine.behavior.IShutdownObserver;
 import org.apache.commons.jcs.io.ObjectInputStreamClassLoaderAware;
 import org.apache.commons.jcs.utils.discovery.UDPDiscoveryMessage.BroadcastType;
-import org.apache.commons.jcs.utils.threadpool.PoolConfiguration;
-import org.apache.commons.jcs.utils.threadpool.PoolConfiguration.WhenBlockedPolicy;
-import org.apache.commons.jcs.utils.threadpool.ThreadPoolManager;
+import org.apache.commons.jcs.utils.threadpool.DaemonThreadFactory;
 import org.apache.commons.logging.Log;
 import org.apache.commons.logging.LogFactory;
 
@@ -57,7 +56,7 @@
     private static final int maxPoolSize = 2;
 
     /** The processor */
-    private ExecutorService pooledExecutor = null;
+    private ThreadPoolExecutor pooledExecutor = null;
 
     /** number of messages received. For debugging and testing. */
     private int cnt = 0;
@@ -92,9 +91,10 @@
         this.multicastPort = multicastPort;
 
         // create a small thread pool to handle a barrage
-        pooledExecutor = ThreadPoolManager.getInstance().createPool(
-        		new PoolConfiguration(false, 0, maxPoolSize, maxPoolSize, 0, WhenBlockedPolicy.DISCARDOLDEST, maxPoolSize), 
-        		"JCS-UDPDiscoveryReceiver-", Thread.MIN_PRIORITY);
+        pooledExecutor = (ThreadPoolExecutor)Executors.newFixedThreadPool(maxPoolSize,
+                new DaemonThreadFactory("JCS-UDPDiscoveryReceiver-", Thread.MIN_PRIORITY));
+        pooledExecutor.setRejectedExecutionHandler(new ThreadPoolExecutor.DiscardOldestPolicy());
+        //pooledExecutor.setMinimumPoolSize(1);
 
         if ( log.isInfoEnabled() )
         {
diff --git a/commons-jcs-core/src/main/java/org/apache/commons/jcs/utils/struct/AbstractLRUMap.java b/commons-jcs-core/src/main/java/org/apache/commons/jcs/utils/struct/AbstractLRUMap.java
index 9effd97..c747f4c 100644
--- a/commons-jcs-core/src/main/java/org/apache/commons/jcs/utils/struct/AbstractLRUMap.java
+++ b/commons-jcs-core/src/main/java/org/apache/commons/jcs/utils/struct/AbstractLRUMap.java
@@ -64,20 +64,22 @@
     private final DoubleLinkedList<LRUElementDescriptor<K, V>> list;
 
     /** Map where items are stored by key. */
-    private final Map<K, LRUElementDescriptor<K, V>> map;
+    private Map<K, LRUElementDescriptor<K, V>> map;
 
-    /** lock to keep map and list synchronous */
+    /** stats */
+    int hitCnt = 0;
+
+    /** stats */
+    int missCnt = 0;
+
+    /** stats */
+    int putCnt = 0;
+
+    /** make configurable */
+    private int chunkSize = 1;
+
     private final Lock lock = new ReentrantLock();
 
-    /** stats */
-    private long hitCnt = 0;
-
-    /** stats */
-    private long missCnt = 0;
-
-    /** stats */
-    private long putCnt = 0;
-
     /**
      * This creates an unbounded version. Setting the max objects will result in spooling on
      * subsequent puts.
@@ -194,7 +196,7 @@
     @Override
     public V get( Object key )
     {
-        V retVal;
+        V retVal = null;
 
         if ( log.isDebugEnabled() )
         {
@@ -203,28 +205,22 @@
 
         LRUElementDescriptor<K, V> me = map.get( key );
 
-        if ( me == null )
-        {
-            missCnt++;
-            retVal = null;
-        }
-        else
+        if ( me != null )
         {
             hitCnt++;
-            retVal = me.getPayload();
-            list.makeFirst( me );
-        }
-
-        if ( log.isDebugEnabled() )
-        {
-            if ( me == null )
-            {
-                log.debug( "LRUMap miss for " + key );
-            }
-            else
+            if ( log.isDebugEnabled() )
             {
                 log.debug( "LRUMap hit for " + key );
             }
+
+            retVal = me.getPayload();
+
+            list.makeFirst( me );
+        }
+        else
+        {
+            missCnt++;
+            log.debug( "LRUMap miss for " + key );
         }
 
         // verifyCache();
@@ -242,23 +238,20 @@
     public V getQuiet( Object key )
     {
         V ce = null;
-        LRUElementDescriptor<K, V> me = map.get( key );
 
+        LRUElementDescriptor<K, V> me = map.get( key );
         if ( me != null )
         {
-            ce = me.getPayload();
-        }
-
-        if ( log.isDebugEnabled() )
-        {
-            if ( me == null )
-            {
-                log.debug( "LRUMap quiet miss for " + key );
-            }
-            else
+            if ( log.isDebugEnabled() )
             {
                 log.debug( "LRUMap quiet hit for " + key );
             }
+
+            ce = me.getPayload();
+        }
+        else if ( log.isDebugEnabled() )
+        {
+            log.debug( "LRUMap quiet miss for " + key );
         }
 
         return ce;
@@ -307,16 +300,17 @@
         putCnt++;
 
         LRUElementDescriptor<K, V> old = null;
-        LRUElementDescriptor<K, V> me = new LRUElementDescriptor<K, V>(key, value);
-
         lock.lock();
         try
         {
-            list.addFirst( me );
-            old = map.put(key, me);
+            // TODO address double synchronization of addFirst, use write lock
+            addFirst( key, value );
+            // this must be synchronized
+            LRUElementDescriptor<K, V> first = list.getFirst();
+            old = map.put(first.getKey(), first);
 
             // If the node was the same as an existing node, remove it.
-            if ( old != null && key.equals(old.getKey()))
+            if ( old != null && first.getKey().equals(old.getKey()))
             {
                 list.remove( old );
             }
@@ -327,6 +321,7 @@
         }
 
         // If the element limit is reached, we need to spool
+
         if (shouldRemove())
         {
             if (log.isDebugEnabled())
@@ -337,6 +332,7 @@
             // The spool will put them in a disk event queue, so there is no
             // need to pre-queue the queuing. This would be a bit wasteful
             // and wouldn't save much time in this synchronous call.
+
             while ( shouldRemove() )
             {
                 lock.lock();
@@ -370,10 +366,10 @@
             {
                 log.debug( "update: After spool map size: " + map.size() );
             }
-            if ( map.size() != list.size() )
+            if ( map.size() != dumpCacheSize() )
             {
-                log.error("update: After spool, size mismatch: map.size() = " + map.size() +
-                        ", linked list size = " + list.size());
+                log.error("update: After spool, size mismatch: map.size() = " + map.size() + ", linked list size = "
+                        + dumpCacheSize());
             }
         }
 
@@ -386,6 +382,37 @@
 
     protected abstract boolean shouldRemove();
 
+
+    /**
+     * Adds a new node to the start of the link list.
+     * <p>
+     * @param key
+     * @param val The feature to be added to the First
+     */
+    private void addFirst(K key, V val)
+    {
+        lock.lock();
+        try
+        {
+            LRUElementDescriptor<K, V> me = new LRUElementDescriptor<K, V>(key, val);
+            list.addFirst( me );
+        }
+        finally
+        {
+            lock.unlock();
+        }
+    }
+
+    /**
+     * Returns the size of the list.
+     * <p>
+     * @return int
+     */
+    private int dumpCacheSize()
+    {
+        return list.size();
+    }
+
     /**
      * Dump the cache entries from first to list for debugging.
      */
@@ -431,8 +458,8 @@
         }
 
         boolean found = false;
-        log.debug( "verifycache: mapContains " + map.size() +
-                " elements, linked list contains " + list.size() + " elements" );
+        log.debug( "verifycache: mapContains " + map.size() + " elements, linked list contains " + dumpCacheSize()
+            + " elements" );
         log.debug( "verifycache: checking linked list by key " );
         for (LRUElementDescriptor<K, V> li = list.getFirst(); li != null; li = (LRUElementDescriptor<K, V>) li.next )
         {
@@ -510,6 +537,37 @@
     }
 
     /**
+     * Logs an error is an element that should be in the cache is not.
+     * <p>
+     * @param key
+     */
+    @SuppressWarnings("unchecked") // No generics for public fields
+    protected void verifyCache( Object key )
+    {
+        if ( !log.isDebugEnabled() )
+        {
+            return;
+        }
+
+        boolean found = false;
+
+        // go through the linked list looking for the key
+        for (LRUElementDescriptor<K, V> li = list.getFirst(); li != null; li = (LRUElementDescriptor<K, V>) li.next )
+        {
+            if ( li.getKey() == key )
+            {
+                found = true;
+                log.debug( "verifycache(key) key match: " + key );
+                break;
+            }
+        }
+        if ( !found )
+        {
+            log.error( "verifycache(key), couldn't find key! : " + key );
+        }
+    }
+
+    /**
      * This is called when an item is removed from the LRU. We just log some information.
      * <p>
      * Children can implement this method for special behavior.
@@ -526,6 +584,24 @@
     }
 
     /**
+     * The chunk size is the number of items to remove when the max is reached. By default it is 1.
+     * <p>
+     * @param chunkSize The chunkSize to set.
+     */
+    public void setChunkSize( int chunkSize )
+    {
+        this.chunkSize = chunkSize;
+    }
+
+    /**
+     * @return Returns the chunkSize.
+     */
+    public int getChunkSize()
+    {
+        return chunkSize;
+    }
+
+    /**
      * @return IStats
      */
     public IStats getStatistics()
@@ -537,9 +613,9 @@
 
         elems.add(new StatElement<Integer>( "List Size", Integer.valueOf(list.size()) ) );
         elems.add(new StatElement<Integer>( "Map Size", Integer.valueOf(map.size()) ) );
-        elems.add(new StatElement<Long>( "Put Count", Long.valueOf(putCnt) ) );
-        elems.add(new StatElement<Long>( "Hit Count", Long.valueOf(hitCnt) ) );
-        elems.add(new StatElement<Long>( "Miss Count", Long.valueOf(missCnt) ) );
+        elems.add(new StatElement<Integer>( "Put Count", Integer.valueOf(putCnt) ) );
+        elems.add(new StatElement<Integer>( "Hit Count", Integer.valueOf(hitCnt) ) );
+        elems.add(new StatElement<Integer>( "Miss Count", Integer.valueOf(missCnt) ) );
 
         stats.setStatElements( elems );
 
diff --git a/commons-jcs-core/src/main/java/org/apache/commons/jcs/utils/struct/LRUMap.java b/commons-jcs-core/src/main/java/org/apache/commons/jcs/utils/struct/LRUMap.java
index 84ff231..fa100b2 100644
--- a/commons-jcs-core/src/main/java/org/apache/commons/jcs/utils/struct/LRUMap.java
+++ b/commons-jcs-core/src/main/java/org/apache/commons/jcs/utils/struct/LRUMap.java
@@ -19,6 +19,8 @@
  * under the License.
  */
 
+import java.util.concurrent.atomic.AtomicInteger;
+
 /**
  *
  * @author Wiktor Niesiobędzki
@@ -30,8 +32,10 @@
  */
 public class LRUMap<K, V> extends AbstractLRUMap<K, V>
 {
+
     /** if the max is less than 0, there is no limit! */
-    private int maxObjects = -1;
+    int maxObjects = -1;
+    AtomicInteger counter = new AtomicInteger(0);
 
     public LRUMap()
     {
@@ -45,7 +49,7 @@
      */
     public LRUMap(int maxObjects)
     {
-        this();
+        super();
         this.maxObjects = maxObjects;
     }
 
@@ -54,4 +58,9 @@
     {
         return maxObjects > 0 && this.size() > maxObjects;
     }
+
+    public Object getMaxCounter()
+    {
+        return maxObjects;
+    }
 }
diff --git a/commons-jcs-core/src/main/java/org/apache/commons/jcs/utils/threadpool/PoolConfiguration.java b/commons-jcs-core/src/main/java/org/apache/commons/jcs/utils/threadpool/PoolConfiguration.java
index f4e886d..05f17e7 100644
--- a/commons-jcs-core/src/main/java/org/apache/commons/jcs/utils/threadpool/PoolConfiguration.java
+++ b/commons-jcs-core/src/main/java/org/apache/commons/jcs/utils/threadpool/PoolConfiguration.java
@@ -27,46 +27,23 @@
 public final class PoolConfiguration
     implements Cloneable
 {
-    /**
-     * DEFAULT SETTINGS
-     */
-    private static final boolean DEFAULT_USE_BOUNDARY = true;
-
-    /** Default queue size limit */
-    private static final int DEFAULT_BOUNDARY_SIZE = 2000;
-
-    /** Default max size */
-    private static final int DEFAULT_MAXIMUM_POOL_SIZE = 150;
-
-    /** Default min */
-    private static final int DEFAULT_MINIMUM_POOL_SIZE = Runtime.getRuntime().availableProcessors();
-
-    /** Default keep alive */
-    private static final int DEFAULT_KEEPALIVE_TIME = 1000 * 60 * 5;
-
-    /** Default when blocked */
-    private static final WhenBlockedPolicy DEFAULT_WHEN_BLOCKED_POLICY = WhenBlockedPolicy.RUN;
-
-    /** Default startup size */
-    private static final int DEFAULT_STARTUP_SIZE = DEFAULT_MINIMUM_POOL_SIZE;
-
     /** Should we bound the queue */
-    private boolean useBoundary = DEFAULT_USE_BOUNDARY;
+    private boolean useBoundary = true;
 
     /** If the queue is bounded, how big can it get */
-    private int boundarySize = DEFAULT_BOUNDARY_SIZE;
+    private int boundarySize = 2000;
 
     /** only has meaning if a boundary is used */
-    private int maximumPoolSize = DEFAULT_MAXIMUM_POOL_SIZE;
+    private int maximumPoolSize = 150;
 
     /**
      * the exact number that will be used in a boundless queue. If the queue has a boundary, more
      * will be created if the queue fills.
      */
-    private int minimumPoolSize = DEFAULT_MINIMUM_POOL_SIZE;
+    private int minimumPoolSize = 4;
 
     /** How long idle threads above the minimum should be kept alive. */
-    private int keepAliveTime = DEFAULT_KEEPALIVE_TIME;
+    private int keepAliveTime = 1000 * 60 * 5;
 
     public enum WhenBlockedPolicy {
         /** abort when queue is full and max threads is reached. */
@@ -86,10 +63,10 @@
     }
 
     /** should be ABORT, BLOCK, RUN, WAIT, DISCARDOLDEST, */
-    private WhenBlockedPolicy whenBlockedPolicy = DEFAULT_WHEN_BLOCKED_POLICY;
+    private WhenBlockedPolicy whenBlockedPolicy = WhenBlockedPolicy.RUN;
 
     /** The number of threads to create on startup */
-    private int startUpSize = DEFAULT_MINIMUM_POOL_SIZE;
+    private int startUpSize = 4;
 
     /**
      * @param useBoundary The useBoundary to set.
@@ -112,9 +89,7 @@
      */
     public PoolConfiguration()
     {
-        this( DEFAULT_USE_BOUNDARY, DEFAULT_BOUNDARY_SIZE, DEFAULT_MAXIMUM_POOL_SIZE,
-              DEFAULT_MINIMUM_POOL_SIZE, DEFAULT_KEEPALIVE_TIME,
-              DEFAULT_WHEN_BLOCKED_POLICY, DEFAULT_STARTUP_SIZE );
+        // nop
     }
 
     /**
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 93ca842..0c9346c 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
@@ -23,14 +23,11 @@
 import java.util.Properties;
 import java.util.concurrent.BlockingQueue;
 import java.util.concurrent.ConcurrentHashMap;
-import java.util.concurrent.ExecutorService;
-import java.util.concurrent.Executors;
 import java.util.concurrent.LinkedBlockingQueue;
-import java.util.concurrent.ScheduledExecutorService;
 import java.util.concurrent.ThreadPoolExecutor;
 import java.util.concurrent.TimeUnit;
 
-import org.apache.commons.jcs.utils.config.PropertySetter;
+import org.apache.commons.jcs.utils.threadpool.PoolConfiguration.WhenBlockedPolicy;
 import org.apache.commons.logging.Log;
 import org.apache.commons.logging.LogFactory;
 
@@ -42,12 +39,30 @@
  * This manager forces you to use a bounded queue. By default it uses the current thread for
  * execution when the buffer is full and no free threads can be created.
  * <p>
- * You can specify the props file to use or pass in a properties object prior to configuration.
+ * You can specify the props file to use or pass in a properties object prior to configuration. By
+ * default it looks for configuration information in thread_pool.properties.
  * <p>
  * If set, the Properties object will take precedence.
  * <p>
- * If a value is not set for a particular pool, the hard coded defaults in <code>PoolConfiguration</code> will be used.
- * You can configure default settings by specifying <code>thread_pool.default</code> in the properties, ie "cache.ccf"
+ * If a value is not set for a particular pool, the hard coded defaults will be used.
+ *
+ * <pre>
+ * int boundarySize_DEFAULT = 2000;
+ *
+ * int maximumPoolSize_DEFAULT = 150;
+ *
+ * int minimumPoolSize_DEFAULT = 4;
+ *
+ * int keepAliveTime_DEFAULT = 1000 * 60 * 5;
+ *
+ * boolean abortWhenBlocked = false;
+ *
+ * String whenBlockedPolicy_DEFAULT = IPoolConfiguration.POLICY_RUN;
+ *
+ * int startUpSize_DEFAULT = 4;
+ * </pre>
+ *
+ * You can configure default settings by specifying a default pool in the properties, ie "cache.ccf"
  * <p>
  * @author Aaron Smuts
  */
@@ -56,8 +71,31 @@
     /** The logger */
     private static final Log log = LogFactory.getLog( ThreadPoolManager.class );
 
+    /**
+     * DEFAULT SETTINGS, these are not final since they can be set via the properties file or object
+     */
+    private static boolean useBoundary_DEFAULT = true;
+
+    /** Default queue size limit */
+    private static int boundarySize_DEFAULT = 2000;
+
+    /** Default max size */
+    private static int maximumPoolSize_DEFAULT = 150;
+
+    /** Default min */
+    private static int minimumPoolSize_DEFAULT = 4;
+
+    /** Default keep alive */
+    private static int keepAliveTime_DEFAULT = 1000 * 60 * 5;
+
+    /** Default when blocked */
+    private static WhenBlockedPolicy whenBlockedPolicy_DEFAULT = WhenBlockedPolicy.RUN;
+
+    /** Default startup size */
+    private static int startUpSize_DEFAULT = 4;
+
     /** The default config, created using property defaults if present, else those above. */
-    private PoolConfiguration defaultConfig;
+    private static PoolConfiguration defaultConfig;
 
     /** the root property name */
     private static final String PROP_NAME_ROOT = "thread_pool";
@@ -65,13 +103,7 @@
     /** default property file name */
     private static final String DEFAULT_PROP_NAME_ROOT = "thread_pool.default";
 
-    /** the scheduler root property name */
-    private static final String PROP_NAME_SCHEDULER_ROOT = "scheduler_pool";
-
-    /** default scheduler property file name */
-    private static final String DEFAULT_PROP_NAME_SCHEDULER_ROOT = "scheduler_pool.default";
-
-   /**
+    /**
      * You can specify the properties to be used to configure the thread pool. Setting this post
      * initialization will have no effect.
      */
@@ -81,42 +113,24 @@
     private static ThreadPoolManager INSTANCE = null;
 
     /** Map of names to pools. */
-    private ConcurrentHashMap<String, ExecutorService> pools;
-
-    /** Map of names to scheduler pools. */
-    private ConcurrentHashMap<String, ScheduledExecutorService> schedulerPools;
+    private ConcurrentHashMap<String, ThreadPoolExecutor> pools;
 
     /**
      * No instances please. This is a singleton.
      */
     private ThreadPoolManager()
     {
-        this.pools = new ConcurrentHashMap<String, ExecutorService>();
-        this.schedulerPools = new ConcurrentHashMap<String, ScheduledExecutorService>();
+        this.pools = new ConcurrentHashMap<String, ThreadPoolExecutor>();
         configure();
     }
 
     /**
      * Creates a pool based on the configuration info.
      * <p>
-     * @param config the pool configuration
-     * @param threadNamePrefix prefix for the thread names of the pool
-     * @return A ThreadPool wrapper
+     * @param config
+     * @return A ThreadPoll wrapper
      */
-    public ExecutorService createPool( PoolConfiguration config, String threadNamePrefix)
-    {
-    	return createPool(config, threadNamePrefix, Thread.NORM_PRIORITY);
-    }
-    
-    /**
-     * Creates a pool based on the configuration info.
-     * <p>
-     * @param config the pool configuration
-     * @param threadNamePrefix prefix for the thread names of the pool
-     * @param threadPriority the priority of the created threads
-     * @return A ThreadPool wrapper
-     */
-    public ExecutorService createPool( PoolConfiguration config, String threadNamePrefix, int threadPriority )
+    private ThreadPoolExecutor createPool( PoolConfiguration config )
     {
         BlockingQueue<Runnable> queue = null;
         if ( config.isUseBoundary() )
@@ -143,7 +157,7 @@
             config.getKeepAliveTime(),
             TimeUnit.MILLISECONDS,
             queue,
-            new DaemonThreadFactory(threadNamePrefix, threadPriority));
+            new DaemonThreadFactory("JCS-ThreadPoolManager-"));
 
         // when blocked policy
         switch (config.getWhenBlockedPolicy())
@@ -173,23 +187,6 @@
     }
 
     /**
-     * Creates a scheduler pool based on the configuration info.
-     * <p>
-     * @param config the pool configuration
-     * @param threadNamePrefix prefix for the thread names of the pool
-     * @param threadPriority the priority of the created threads
-     * @return A ScheduledExecutorService
-     */
-    public ScheduledExecutorService createSchedulerPool( PoolConfiguration config, String threadNamePrefix, int threadPriority )
-    {
-    	ScheduledExecutorService scheduler = Executors.newScheduledThreadPool(
-    			config.getMaximumPoolSize(), 
-    			new DaemonThreadFactory(threadNamePrefix, threadPriority));
-
-        return scheduler;
-    }
-    
-    /**
      * Returns a configured instance of the ThreadPoolManger To specify a configuration file or
      * Properties object to use call the appropriate setter prior to calling getInstance.
      * <p>
@@ -211,46 +208,34 @@
     {
         if ( INSTANCE != null )
         {
-            for ( ExecutorService pool : INSTANCE.pools.values() )
+            for ( String poolName : INSTANCE.getPoolNames())
             {
                 try
                 {
-                    pool.shutdownNow();
+                    INSTANCE.getPool(poolName).shutdownNow();
                 }
                 catch (Throwable t)
                 {
-                    log.warn("Failed to close pool " + pool, t);
+                    log.warn("Failed to close pool " + poolName, t);
                 }
             }
-            
-            for ( ScheduledExecutorService pool : INSTANCE.schedulerPools.values() )
-            {
-                try
-                {
-                    pool.shutdownNow();
-                }
-                catch (Throwable t)
-                {
-                    log.warn("Failed to close pool " + pool, t);
-                }
-            }
-            
+
             INSTANCE = null;
         }
     }
 
     /**
-     * Returns an executor service by name. If a service by this name does not exist in the configuration file or
+     * Returns a pool by name. If a pool by this name does not exist in the configuration file or
      * properties, one will be created using the default values.
      * <p>
-     * Services are lazily created.
+     * Pools are lazily created.
      * <p>
      * @param name
-     * @return The executor service configured for the name.
+     * @return The thread pool configured for the name.
      */
-    public ExecutorService getExecutorService( String name )
+    public ThreadPoolExecutor getPool( String name )
     {
-    	ExecutorService pool = pools.get( name );
+        ThreadPoolExecutor pool = pools.get( name );
 
         if ( pool == null )
         {
@@ -260,17 +245,12 @@
             }
 
             PoolConfiguration config = loadConfig( PROP_NAME_ROOT + "." + name );
-            ExecutorService _pool = createPool( config, "JCS-ThreadPoolManager-" + name + "-" );
-            pool = pools.putIfAbsent( name, _pool );
-            if (pool == null)
+            pool = createPool( config );
+            ThreadPoolExecutor _pool = pools.putIfAbsent( name, pool );
+            if (_pool != null)
             {
                 pool = _pool;
             }
-            else
-            {
-            	// already created in another thread
-            	_pool.shutdownNow();
-            }
 
             if ( log.isDebugEnabled() )
             {
@@ -280,61 +260,6 @@
 
         return pool;
     }
-    
-    /**
-     * Returns a pool by name. If a pool by this name does not exist in the configuration file or
-     * properties, one will be created using the default values.
-     * <p>
-     * Pools are lazily created.
-     * <p>
-     * @param name
-     * @return The thread pool configured for the name.
-     * 
-     * @deprecated Use getExecutorService() instead
-     */
-    @Deprecated
-	public ThreadPoolExecutor getPool( String name )
-    {
-    	return (ThreadPoolExecutor) getExecutorService(name);
-    }
-
-    /**
-     * Returns a scheduler pool by name. If a pool by this name does not exist in the configuration file or
-     * properties, one will be created using the default values.
-     * <p>
-     * Pools are lazily created.
-     * <p>
-     * @param name
-     * @return The scheduler pool configured for the name.
-     */
-    public ScheduledExecutorService getSchedulerPool( String name )
-    {
-    	ScheduledExecutorService pool = schedulerPools.get( name );
-
-        if ( pool == null )
-        {
-            if ( log.isDebugEnabled() )
-            {
-                log.debug( "Creating scheduler pool for name [" + name + "]" );
-            }
-
-            PoolConfiguration defaultSchedulerConfig = loadConfig( DEFAULT_PROP_NAME_SCHEDULER_ROOT );
-            PoolConfiguration config = loadConfig( PROP_NAME_SCHEDULER_ROOT + "." + name, defaultSchedulerConfig );
-            ScheduledExecutorService _pool = createSchedulerPool( config, "JCS-ThreadPoolManager-" + name + "-", Thread.NORM_PRIORITY );
-            pool = schedulerPools.putIfAbsent( name, _pool );
-            if (pool == null)
-            {
-                pool = _pool;
-            }
-            else
-            {
-            	// already created in another thread
-            	_pool.shutdownNow();
-            }
-        }
-
-        return pool;
-    }
 
     /**
      * Returns the names of all configured pools.
@@ -360,7 +285,7 @@
     /**
      * Initialize the ThreadPoolManager and create all the pools defined in the configuration.
      */
-    private void configure()
+    private static void configure()
     {
         if ( log.isDebugEnabled() )
         {
@@ -375,36 +300,88 @@
 
         // set intial default and then override if new
         // settings are available
-        defaultConfig = new PoolConfiguration();
+        defaultConfig = new PoolConfiguration( useBoundary_DEFAULT, boundarySize_DEFAULT, maximumPoolSize_DEFAULT,
+                                               minimumPoolSize_DEFAULT, keepAliveTime_DEFAULT,
+                                               whenBlockedPolicy_DEFAULT, startUpSize_DEFAULT );
+
         defaultConfig = loadConfig( DEFAULT_PROP_NAME_ROOT );
     }
 
     /**
-     * Configures the PoolConfiguration settings.
+     * Configures the default PoolConfiguration settings.
      * <p>
-     * @param root the configuration key prefix
+     * @param root
      * @return PoolConfiguration
      */
-    private PoolConfiguration loadConfig( String root )
+    private static PoolConfiguration loadConfig( String root )
     {
-    	return loadConfig(root, defaultConfig);
-    }
-    
-    /**
-     * Configures the PoolConfiguration settings.
-     * <p>
-     * @param root the configuration key prefix
-     * @param defaultPoolConfiguration the default configuration
-     * @return PoolConfiguration
-     */
-    private PoolConfiguration loadConfig( String root, PoolConfiguration defaultPoolConfiguration )
-    {
-        PoolConfiguration config = defaultPoolConfiguration.clone();
-        PropertySetter.setProperties( config, props, root + "." );
+        PoolConfiguration config = defaultConfig.clone();
 
-        if ( log.isDebugEnabled() )
+        try
         {
-            log.debug( root + " PoolConfiguration = " + config );
+            config.setUseBoundary( Boolean.parseBoolean( props.getProperty( root + ".useBoundary", "false" ) ) );
+        }
+        catch ( NumberFormatException nfe )
+        {
+            log.error( "useBoundary not a boolean.", nfe );
+        }
+
+        // load default if they exist
+        try
+        {
+            config.setBoundarySize( Integer.parseInt( props.getProperty( root + ".boundarySize", "2000" ) ) );
+        }
+        catch ( NumberFormatException nfe )
+        {
+            log.error( "boundarySize not a number.", nfe );
+        }
+
+        // maximum pool size
+        try
+        {
+            config.setMaximumPoolSize( Integer.parseInt( props.getProperty( root + ".maximumPoolSize", "150" ) ) );
+        }
+        catch ( NumberFormatException nfe )
+        {
+            log.error( "maximumPoolSize not a number.", nfe );
+        }
+
+        // minimum pool size
+        try
+        {
+            config.setMinimumPoolSize( Integer.parseInt( props.getProperty( root + ".minimumPoolSize", "4" ) ) );
+        }
+        catch ( NumberFormatException nfe )
+        {
+            log.error( "minimumPoolSize not a number.", nfe );
+        }
+
+        // keep alive
+        try
+        {
+            config.setKeepAliveTime( Integer.parseInt( props.getProperty( root + ".keepAliveTime", "300000" ) ) );
+        }
+        catch ( NumberFormatException nfe )
+        {
+            log.error( "keepAliveTime not a number.", nfe );
+        }
+
+        // when blocked
+        config.setWhenBlockedPolicy( props.getProperty( root + ".whenBlockedPolicy", "RUN" ) );
+
+        // startupsize
+        try
+        {
+            config.setStartUpSize( Integer.parseInt( props.getProperty( root + ".startUpSize", "4" ) ) );
+        }
+        catch ( NumberFormatException nfe )
+        {
+            log.error( "startUpSize not a number.", nfe );
+        }
+
+        if ( log.isInfoEnabled() )
+        {
+            log.info( root + " PoolConfiguration = " + config );
         }
 
         return config;
diff --git a/commons-jcs-core/src/test/java/org/apache/commons/jcs/auxiliary/remote/RemoteCacheNoWaitUnitTest.java b/commons-jcs-core/src/test/java/org/apache/commons/jcs/auxiliary/remote/RemoteCacheNoWaitUnitTest.java
index 231841a..fe671ae 100644
--- a/commons-jcs-core/src/test/java/org/apache/commons/jcs/auxiliary/remote/RemoteCacheNoWaitUnitTest.java
+++ b/commons-jcs-core/src/test/java/org/apache/commons/jcs/auxiliary/remote/RemoteCacheNoWaitUnitTest.java
@@ -1,16 +1,5 @@
 package org.apache.commons.jcs.auxiliary.remote;
 
-import java.util.HashMap;
-import java.util.HashSet;
-import java.util.Map;
-import java.util.Set;
-
-import org.apache.commons.jcs.engine.CacheElement;
-import org.apache.commons.jcs.engine.CacheStatus;
-import org.apache.commons.jcs.engine.behavior.ICacheElement;
-import org.apache.commons.jcs.engine.behavior.ICacheEventQueue;
-import org.apache.commons.jcs.utils.timing.SleepUtil;
-
 /*
  * Licensed to the Apache Software Foundation (ASF) under one
  * or more contributor license agreements.  See the NOTICE file
@@ -31,6 +20,16 @@
  */
 
 import junit.framework.TestCase;
+import org.apache.commons.jcs.engine.CacheElement;
+import org.apache.commons.jcs.engine.CacheStatus;
+import org.apache.commons.jcs.engine.behavior.ICacheElement;
+import org.apache.commons.jcs.engine.behavior.ICacheEventQueue;
+import org.apache.commons.jcs.utils.timing.SleepUtil;
+
+import java.util.HashMap;
+import java.util.HashSet;
+import java.util.Map;
+import java.util.Set;
 
 /**
  * Unit tests for the remote cache no wait. The no wait manages a queue on top of the client.
@@ -199,7 +198,7 @@
         // DO WORK
         noWait.update( element );
         SleepUtil.sleepAtLeast( 10 );
-        // ICacheEventQueue<String, String> originalQueue = noWait.getCacheEventQueue();
+        ICacheEventQueue<String, String> originalQueue = noWait.getCacheEventQueue();
 
         noWait.fixCache( service );
 
@@ -209,7 +208,7 @@
 
         // VERIFY
         assertEquals( "Wrong status", service, client.fixed );
-        // assertFalse( "Original queue should not alive", originalQueue.isAlive() );
+        assertFalse( "Original queue should not alive", originalQueue.isAlive() );
         assertTrue( "New queue should be alive." + newQueue, newQueue.isAlive() );
     }
 }
diff --git a/commons-jcs-core/src/test/java/org/apache/commons/jcs/engine/CacheEventQueueFactoryUnitTest.java b/commons-jcs-core/src/test/java/org/apache/commons/jcs/engine/CacheEventQueueFactoryUnitTest.java
index 60b72f3..3925b63 100644
--- a/commons-jcs-core/src/test/java/org/apache/commons/jcs/engine/CacheEventQueueFactoryUnitTest.java
+++ b/commons-jcs-core/src/test/java/org/apache/commons/jcs/engine/CacheEventQueueFactoryUnitTest.java
@@ -1,10 +1,5 @@
 package org.apache.commons.jcs.engine;
 
-import org.apache.commons.jcs.auxiliary.remote.MockRemoteCacheListener;
-import org.apache.commons.jcs.engine.behavior.ICacheEventQueue;
-import org.apache.commons.jcs.engine.behavior.ICacheEventQueue.QueueType;
-import org.apache.commons.jcs.engine.behavior.ICacheListener;
-
 /*
  * Licensed to the Apache Software Foundation (ASF) under one
  * or more contributor license agreements.  See the NOTICE file
@@ -25,6 +20,10 @@
  */
 
 import junit.framework.TestCase;
+import org.apache.commons.jcs.auxiliary.remote.MockRemoteCacheListener;
+import org.apache.commons.jcs.engine.behavior.ICacheEventQueue;
+import org.apache.commons.jcs.engine.behavior.ICacheEventQueue.QueueType;
+import org.apache.commons.jcs.engine.behavior.ICacheListener;
 
 /** Unit tests for the CacheEventQueueFactory */
 public class CacheEventQueueFactoryUnitTest
@@ -45,7 +44,7 @@
 
         // VERIFY
         assertNotNull( "Should have a result", result );
-        assertTrue( "Wrong type", result.getQueueType() == QueueType.SINGLE );
+        assertTrue( "Wrong type", result instanceof CacheEventQueue );
     }
 
     /** Test create */
@@ -63,6 +62,6 @@
 
         // VERIFY
         assertNotNull( "Should have a result", result );
-        assertTrue( "Wrong type", result.getQueueType() == QueueType.POOLED );
+        assertTrue( "Wrong type", result instanceof PooledCacheEventQueue );
     }
 }
diff --git a/commons-jcs-core/src/test/java/org/apache/commons/jcs/engine/EventQueueConcurrentLoadTest.java b/commons-jcs-core/src/test/java/org/apache/commons/jcs/engine/EventQueueConcurrentLoadTest.java
index 799ebf4..8aa4bb8 100644
--- a/commons-jcs-core/src/test/java/org/apache/commons/jcs/engine/EventQueueConcurrentLoadTest.java
+++ b/commons-jcs-core/src/test/java/org/apache/commons/jcs/engine/EventQueueConcurrentLoadTest.java
@@ -21,13 +21,13 @@
 
 import java.io.IOException;
 
-import org.apache.commons.jcs.engine.behavior.ICacheElement;
-import org.apache.commons.jcs.engine.behavior.ICacheListener;
-
 import junit.extensions.ActiveTestSuite;
 import junit.framework.Test;
 import junit.framework.TestCase;
 
+import org.apache.commons.jcs.engine.behavior.ICacheElement;
+import org.apache.commons.jcs.engine.behavior.ICacheListener;
+
 /**
  * This test case is designed to makes sure there are no deadlocks in the event queue. The time to
  * live should be set to a very short interval to make a deadlock more likely.
@@ -109,6 +109,16 @@
             }
         } );
 
+        suite.addTest( new EventQueueConcurrentLoadTest( "testStopProcessing1" )
+        {
+            @Override
+            public void runTest()
+                throws Exception
+            {
+                this.runStopProcessingTest();
+            }
+        } );
+
         suite.addTest( new EventQueueConcurrentLoadTest( "testRunPutTest4" )
         {
             @Override
@@ -129,6 +139,16 @@
             }
         } );
 
+        suite.addTest( new EventQueueConcurrentLoadTest( "testStopProcessing2" )
+        {
+            @Override
+            public void runTest()
+                throws Exception
+            {
+                this.runStopProcessingTest();
+            }
+        } );
+
         suite.addTest( new EventQueueConcurrentLoadTest( "testRunPutDelayTest" )
         {
             @Override
@@ -202,6 +222,16 @@
     }
 
     /**
+     * Add remove events to the event queue.
+     * @throws Exception
+     */
+    public void runStopProcessingTest()
+        throws Exception
+    {
+        queue.stopProcessing();
+    }
+
+    /**
      * Test putting and a delay. Waits until queue is empty to start.
      * @param end
      * @param expectedPutCount
diff --git a/commons-jcs-core/src/test/java/org/apache/commons/jcs/utils/struct/LRUMapConcurrentUnitTest.java b/commons-jcs-core/src/test/java/org/apache/commons/jcs/utils/struct/LRUMapConcurrentUnitTest.java
index 6ce5625..09b6005 100644
--- a/commons-jcs-core/src/test/java/org/apache/commons/jcs/utils/struct/LRUMapConcurrentUnitTest.java
+++ b/commons-jcs-core/src/test/java/org/apache/commons/jcs/utils/struct/LRUMapConcurrentUnitTest.java
@@ -1,7 +1,5 @@
 package org.apache.commons.jcs.utils.struct;
 
-import java.util.Iterator;
-
 /*
  * Licensed to the Apache Software Foundation (ASF) under one
  * or more contributor license agreements.  See the NOTICE file
@@ -25,6 +23,8 @@
 import junit.framework.TestCase;
 import junit.framework.TestSuite;
 
+import java.util.Iterator;
+
 /**
  * Tests the LRUMap
  *
@@ -150,6 +150,7 @@
     {
         int total = 10;
         LRUMap<String, String> map = new LRUMap<String, String>( total );
+        map.setChunkSize( 1 );
 
         // put the max in
         for ( int i = 0; i < total; i++ )
@@ -188,6 +189,7 @@
     {
         int total = 10000;
         LRUMap<String, String> map = new LRUMap<String, String>( total );
+        map.setChunkSize( 1 );
 
         // put the max in
         for ( int i = 0; i < total * 2; i++ )
@@ -199,6 +201,7 @@
         for ( int i = total - 1; i >= 0; i-- )
         {
             assertNull( map.get( i + ":key" ) );
+
         }
 
         // get the total to total *2 items out, these should be found.
@@ -209,6 +212,7 @@
         }
 
 //        System.out.println( map.getStatistics() );
+
     }
 
     /**
diff --git a/commons-jcs-core/src/test/java/org/apache/commons/jcs/utils/struct/LRUMapPerformanceTest.java b/commons-jcs-core/src/test/java/org/apache/commons/jcs/utils/struct/LRUMapPerformanceTest.java
index e11d7ab..bbf851f 100644
--- a/commons-jcs-core/src/test/java/org/apache/commons/jcs/utils/struct/LRUMapPerformanceTest.java
+++ b/commons-jcs-core/src/test/java/org/apache/commons/jcs/utils/struct/LRUMapPerformanceTest.java
@@ -1,9 +1,5 @@
 package org.apache.commons.jcs.utils.struct;
 
-import java.util.Map;
-
-import org.apache.commons.jcs.JCSvsHashtablePerformanceTest;
-
 /*
  * Licensed to the Apache Software Foundation (ASF) under one
  * or more contributor license agreements.  See the NOTICE file
@@ -26,6 +22,9 @@
 import junit.framework.Test;
 import junit.framework.TestCase;
 import junit.framework.TestSuite;
+import org.apache.commons.jcs.JCSvsHashtablePerformanceTest;
+
+import java.util.Map;
 
 /**
  * This ensures that the jcs version of the LRU map is as fast as the commons
@@ -107,7 +106,7 @@
 
         try
         {
-            LRUMap<String, String> cache = new LRUMap<String, String>( tries );
+            Map<String, String> cache = new LRUMap<String, String>( tries );
 
             for ( int j = 0; j < loops; j++ )
             {
@@ -135,12 +134,9 @@
                 System.out.println( name + " get time for " + tries + " = " + time + "; millis per = " + tPer );
 
                 ///////////////////////////////////////////////////////////////
-                cache2Name = "LRUMap (commons)";
+                cache2Name = "LRUMapJCS (commons)";
                 //or LRUMapJCS
                 Map<String, String> cache2 = new org.apache.commons.collections4.map.LRUMap<String, String>( tries );
-//                Map<String, String> cache2 = new ConcurrentLinkedHashMap.Builder<String, String>()
-//                        .maximumWeightedCapacity( tries )
-//                        .build();
                 //cache2Name = "Hashtable";
                 //Hashtable cache2 = new Hashtable();
                 start = System.currentTimeMillis();
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 1c89cc5..e2210a1 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
@@ -21,14 +21,12 @@
 
 import java.util.ArrayList;
 import java.util.Properties;
-import java.util.concurrent.RejectedExecutionHandler;
 import java.util.concurrent.ThreadPoolExecutor;
-import java.util.concurrent.TimeUnit;
-
-import org.apache.commons.jcs.utils.props.PropertyLoader;
 
 import junit.framework.TestCase;
 
+import org.apache.commons.jcs.utils.props.PropertyLoader;
+
 /**
  * Verify that the manager can create pools as intended by the default and
  * specified file names.
@@ -65,39 +63,6 @@
     }
 
     /**
-     * Make sure it can load a certain configuration
-     */
-    public void testSpecialConfig()
-    {
-        Properties props = PropertyLoader.loadProperties( "thread_pool.properties" );
-        ThreadPoolManager.setProps( props );
-        ThreadPoolManager mgr = ThreadPoolManager.getInstance();
-        assertNotNull( mgr );
-
-        ThreadPoolExecutor pool = mgr.getPool( "aborttest" );
-        assertNotNull( pool );
-
-        int poolSize = pool.getCorePoolSize();
-        int expectedPoolSize = Integer.parseInt( props.getProperty( "thread_pool.aborttest.startUpSize" ) );
-        assertEquals( expectedPoolSize, poolSize);
-
-        int minPoolSize = pool.getPoolSize();
-        int expectedMinPoolSize = Integer.parseInt( props.getProperty( "thread_pool.aborttest.minimumPoolSize" ) );
-        assertEquals( expectedMinPoolSize, minPoolSize );
-
-        int maxPoolSize = pool.getMaximumPoolSize();
-        int expectedMaxPoolSize = Integer.parseInt( props.getProperty( "thread_pool.aborttest.maximumPoolSize" ) );
-        assertEquals( expectedMaxPoolSize, maxPoolSize );
-
-        long keepAliveTime = pool.getKeepAliveTime(TimeUnit.MILLISECONDS);
-        long expectedKeepAliveTime = Long.parseLong( props.getProperty( "thread_pool.aborttest.keepAliveTime" ) );
-        assertEquals( expectedKeepAliveTime, keepAliveTime );
-        
-        RejectedExecutionHandler whenBlockedPolicy = pool.getRejectedExecutionHandler();
-        assertTrue( whenBlockedPolicy instanceof ThreadPoolExecutor.AbortPolicy );
-    }
-    
-    /**
      * Try to get an undefined pool from an existing default file.
      */
     public void testDefaultConfigUndefinedPool()
@@ -126,10 +91,10 @@
         assertNotNull( mgr );
 
         String poolName1 = "testGetPoolNames1";
-        mgr.getExecutorService( poolName1 );
+        mgr.getPool( poolName1 );
 
         String poolName2 = "testGetPoolNames2";
-        mgr.getExecutorService( poolName2 );
+        mgr.getPool( poolName2 );
 
         ArrayList<String> names = mgr.getPoolNames();
         assertTrue( "Should have name in list.", names.contains( poolName1 ) );
diff --git a/commons-jcs-core/src/test/test-conf/thread_pool.properties b/commons-jcs-core/src/test/test-conf/thread_pool.properties
index b6a3326..cbf5284 100644
--- a/commons-jcs-core/src/test/test-conf/thread_pool.properties
+++ b/commons-jcs-core/src/test/test-conf/thread_pool.properties
@@ -44,13 +44,13 @@
 thread_pool.maxtest.whenBlockedPolicy=RUN
 thread_pool.maxtest.startUpSize=5
 
-# abort test thread pool config
-thread_pool.aborttest.boundarySize=1
-thread_pool.aborttest.maximumPoolSize=11
-thread_pool.aborttest.minimumPoolSize=1
-thread_pool.aborttest.keepAliveTime=1
-thread_pool.aborttest.whenBlockedPolicy=ABORT
-thread_pool.aborttest.startUpSize=1
+# wait test thread pool config
+thread_pool.waittest.boundarySize=1
+thread_pool.waittest.maximumPoolSize=11
+thread_pool.waittest.minimumPoolSize=1
+thread_pool.waittest.keepAliveTime=1
+thread_pool.waittest.whenBlockedPolicy=WAIT
+thread_pool.waittest.startUpSize=1
 
 # with boundary test thread pool config
 thread_pool.withbound.useBoundary=true
@@ -58,7 +58,7 @@
 thread_pool.withbound.maximumPoolSize=11
 thread_pool.withbound.minimumPoolSize=1
 thread_pool.withbound.keepAliveTime=1
-thread_pool.withbound.whenBlockedPolicy=ABORT
+thread_pool.withbound.whenBlockedPolicy=WAIT
 thread_pool.withbound.startUpSize=1
 
 
@@ -68,5 +68,5 @@
 thread_pool.nobound.maximumPoolSize=11
 thread_pool.nobound.minimumPoolSize=1
 thread_pool.nobound.keepAliveTime=1
-thread_pool.nobound.whenBlockedPolicy=ABORT
+thread_pool.nobound.whenBlockedPolicy=WAIT
 thread_pool.nobound.startUpSize=1
diff --git a/commons-jcs-dist/pom.xml b/commons-jcs-dist/pom.xml
index 559b600..0991542 100644
--- a/commons-jcs-dist/pom.xml
+++ b/commons-jcs-dist/pom.xml
@@ -32,9 +32,9 @@
   <description>Creates the Apache Commons JCS multimodule distribution.</description>
 
   <scm>
-    <connection>scm:svn:http://svn.apache.org/repos/asf/commons/proper/jcs/trunk/commons-jcs-dist</connection>
-    <developerConnection>scm:svn:https://svn.apache.org/repos/asf/commons/proper/jcs/trunk/commons-jcs-dist</developerConnection>
-    <url>http://svn.apache.org/viewvc/commons/proper/jcs/trunk/commons-jcs-dist</url>
+    <connection>scm:svn:http://svn.apache.org/repos/asf/commons/proper/jcs/branches/commons-jcs-2.1-RC/commons-jcs-dist</connection>
+    <developerConnection>scm:svn:https://svn.apache.org/repos/asf/commons/proper/jcs/branches/commons-jcs-2.1-RC/commons-jcs-dist</developerConnection>
+    <url>http://svn.apache.org/viewvc/commons/proper/jcs/branches/commons-jcs-2.1-RC/commons-jcs-dist</url>
   </scm>
 
   <!-- NOTE: These dependency declarations are only required to sort this project to the 
diff --git a/commons-jcs-jcache-extras/pom.xml b/commons-jcs-jcache-extras/pom.xml
index 091cbea..741923f 100644
--- a/commons-jcs-jcache-extras/pom.xml
+++ b/commons-jcs-jcache-extras/pom.xml
@@ -30,9 +30,9 @@
   <name>Apache Commons JCS :: JCache Extras</name>
 
   <scm>
-    <connection>scm:svn:http://svn.apache.org/repos/asf/commons/proper/jcs/trunk/commons-jcs-jcache-extras</connection>
-    <developerConnection>scm:svn:https://svn.apache.org/repos/asf/commons/proper/jcs/trunk/commons-jcs-jcache-extras</developerConnection>
-    <url>http://svn.apache.org/viewvc/commons/proper/jcs/trunk/commons-jcs-jcache-extras</url>
+    <connection>scm:svn:http://svn.apache.org/repos/asf/commons/proper/jcs/branches/commons-jcs-2.1-RC/commons-jcs-jcache-extras</connection>
+    <developerConnection>scm:svn:https://svn.apache.org/repos/asf/commons/proper/jcs/branches/commons-jcs-2.1-RC/commons-jcs-jcache-extras</developerConnection>
+    <url>http://svn.apache.org/viewvc/commons/proper/jcs/branches/commons-jcs-2.1-RC/commons-jcs-jcache-extras</url>
   </scm>
 
   <dependencies>
diff --git a/commons-jcs-jcache-openjpa/pom.xml b/commons-jcs-jcache-openjpa/pom.xml
index a83133b..b7efa57 100644
--- a/commons-jcs-jcache-openjpa/pom.xml
+++ b/commons-jcs-jcache-openjpa/pom.xml
@@ -30,9 +30,9 @@
   <name>Apache Commons JCS :: JCache OpenJPA</name>
 
   <scm>
-    <connection>scm:svn:http://svn.apache.org/repos/asf/commons/proper/jcs/trunk/commons-jcs-jcache-openjpa</connection>
-    <developerConnection>scm:svn:https://svn.apache.org/repos/asf/commons/proper/jcs/trunk/commons-jcs-jcache-openjpa</developerConnection>
-    <url>http://svn.apache.org/viewvc/commons/proper/jcs/trunk/commons-jcs-jcache-openjpa</url>
+    <connection>scm:svn:http://svn.apache.org/repos/asf/commons/proper/jcs/branches/commons-jcs-2.1-RC/commons-jcs-jcache-openjpa</connection>
+    <developerConnection>scm:svn:https://svn.apache.org/repos/asf/commons/proper/jcs/branches/commons-jcs-2.1-RC/commons-jcs-jcache-openjpa</developerConnection>
+    <url>http://svn.apache.org/viewvc/commons/proper/jcs/branches/commons-jcs-2.1-RC/commons-jcs-jcache-openjpa</url>
   </scm>
 
   <dependencies>
diff --git a/commons-jcs-jcache/pom.xml b/commons-jcs-jcache/pom.xml
index 15d2c8d..b6fb71e 100644
--- a/commons-jcs-jcache/pom.xml
+++ b/commons-jcs-jcache/pom.xml
@@ -32,9 +32,9 @@
   <name>Apache Commons JCS :: JCache</name>
 
   <scm>
-    <connection>scm:svn:http://svn.apache.org/repos/asf/commons/proper/jcs/trunk/commons-jcs-jcache</connection>
-    <developerConnection>scm:svn:https://svn.apache.org/repos/asf/commons/proper/jcs/trunk/commons-jcs-jcache</developerConnection>
-    <url>http://svn.apache.org/viewvc/commons/proper/jcs/trunk/commons-jcs-jcache</url>
+    <connection>scm:svn:http://svn.apache.org/repos/asf/commons/proper/jcs/branches/commons-jcs-2.1-RC/commons-jcs-jcache</connection>
+    <developerConnection>scm:svn:https://svn.apache.org/repos/asf/commons/proper/jcs/branches/commons-jcs-2.1-RC/commons-jcs-jcache</developerConnection>
+    <url>http://svn.apache.org/viewvc/commons/proper/jcs/branches/commons-jcs-2.1-RC/commons-jcs-jcache</url>
   </scm>
 
   <dependencies>
diff --git a/commons-jcs-tck-tests/pom.xml b/commons-jcs-tck-tests/pom.xml
index 7ecb150..4e61e0b 100644
--- a/commons-jcs-tck-tests/pom.xml
+++ b/commons-jcs-tck-tests/pom.xml
@@ -39,9 +39,9 @@
   <name>Apache Commons JCS :: JCache TCK</name>
 
   <scm>
-    <connection>scm:svn:http://svn.apache.org/repos/asf/commons/proper/jcs/trunk/commons-jcs-tck-tests</connection>
-    <developerConnection>scm:svn:https://svn.apache.org/repos/asf/commons/proper/jcs/trunk/commons-jcs-tck-tests</developerConnection>
-    <url>http://svn.apache.org/viewvc/commons/proper/jcs/trunk/commons-jcs-tck-tests</url>
+    <connection>scm:svn:http://svn.apache.org/repos/asf/commons/proper/jcs/branches/commons-jcs-2.1-RC/commons-jcs-tck-tests</connection>
+    <developerConnection>scm:svn:https://svn.apache.org/repos/asf/commons/proper/jcs/branches/commons-jcs-2.1-RC/commons-jcs-tck-tests</developerConnection>
+    <url>http://svn.apache.org/viewvc/commons/proper/jcs/branches/commons-jcs-2.1-RC/commons-jcs-tck-tests</url>
   </scm>
 
   <properties>
diff --git a/pom.xml b/pom.xml
index c51c573..094c6b2 100644
--- a/pom.xml
+++ b/pom.xml
@@ -51,9 +51,9 @@
   </issueManagement>
 
   <scm>
-    <connection>scm:svn:http://svn.apache.org/repos/asf/commons/proper/jcs/trunk</connection>
-    <developerConnection>scm:svn:https://svn.apache.org/repos/asf/commons/proper/jcs/trunk</developerConnection>
-    <url>http://svn.apache.org/viewvc/commons/proper/jcs/trunk</url>
+    <connection>scm:svn:http://svn.apache.org/repos/asf/commons/proper/jcs/branches/commons-jcs-2.1-RC</connection>
+    <developerConnection>scm:svn:https://svn.apache.org/repos/asf/commons/proper/jcs/branches/commons-jcs-2.1-RC</developerConnection>
+    <url>http://svn.apache.org/viewvc/commons/proper/jcs/branches/commons-jcs-2.1-RC</url>
   </scm>
 
   <mailingLists>
@@ -519,8 +519,8 @@
     <maven.compiler.target>1.6</maven.compiler.target>
 
     <commons.componentid>jcs</commons.componentid>
-    <commons.release.version>2.0</commons.release.version>
-    <commons.release.name>commons-jcs-dist-2.0</commons.release.name>
+    <commons.release.version>2.1</commons.release.version>
+    <commons.release.name>commons-jcs-dist-2.1</commons.release.name>
     <commons.release.desc>(Java 6.0+)</commons.release.desc>
     <!-- The RC version used in the staging repository URL. -->
     <commons.rc.version>RC1</commons.rc.version>