Index: src/java/org/apache/solr/common/util/ConcurrentLRUCache.java
===================================================================
--- src/java/org/apache/solr/common/util/ConcurrentLRUCache.java	(revision 714218)
+++ src/java/org/apache/solr/common/util/ConcurrentLRUCache.java	(working copy)
@@ -9,6 +9,7 @@
 import java.util.concurrent.atomic.AtomicInteger;
 import java.util.concurrent.atomic.AtomicLong;
 import java.util.concurrent.locks.ReentrantLock;
+import java.lang.ref.WeakReference;
 
 /**
  * A LRU cache implementation based upon ConcurrentHashMap and other techniques to reduce
@@ -22,11 +23,10 @@
  * @version $Id$
  * @since solr 1.4
  */
-public class ConcurrentLRUCache {
+public class ConcurrentLRUCache<K,V> {
 
   private final ConcurrentHashMap<Object, CacheEntry> map;
   private final int upperWaterMark, lowerWaterMark;
-  private volatile boolean stop = false;
   private final ReentrantLock markAndSweepLock = new ReentrantLock(true);
   private boolean isCleaning = false;  // not volatile... piggybacked on other volatile vars
   private final boolean newThreadForCleanup;
@@ -34,8 +34,12 @@
   private final Stats stats = new Stats();
   private final int acceptableWaterMark;
   private long oldestEntry = 0;  // not volatile, only accessed in the cleaning method
+  private final EvictionListener<K,V> evictionListener;
+  private CleanupThread cleanupThread ;
 
-  public ConcurrentLRUCache(int upperWaterMark, final int lowerWaterMark, int acceptableWatermark, int initialSize, boolean runCleanupThread, boolean runNewThreadForCleanup, final int delay) {
+  public ConcurrentLRUCache(int upperWaterMark, final int lowerWaterMark, int acceptableWatermark,
+                            int initialSize, boolean runCleanupThread, boolean runNewThreadForCleanup,
+                            EvictionListener<K,V> evictionListener) {
     if (upperWaterMark < 1) throw new IllegalArgumentException("upperWaterMark must be > 0");
     if (lowerWaterMark >= upperWaterMark)
       throw new IllegalArgumentException("lowerWaterMark must be  < upperWaterMark");
@@ -44,26 +48,57 @@
     this.upperWaterMark = upperWaterMark;
     this.lowerWaterMark = lowerWaterMark;
     this.acceptableWaterMark = acceptableWatermark;
+    this.evictionListener = evictionListener;
     if (runCleanupThread) {
-      new Thread() {
-        public void run() {
-          while (true) {
-            if (stop) break;
-            try {
-              Thread.sleep(delay * 1000);
-            } catch (InterruptedException e) {/*no op*/ }
-            markAndSweep();
+      cleanupThread = new CleanupThread(this);
+      cleanupThread.start();
+    }
+  }
+
+  private static class CleanupThread extends Thread {
+    private final Object monitor = new Object();
+    private WeakReference<ConcurrentLRUCache> cache;
+
+
+    private boolean stop = false;
+
+    public CleanupThread(ConcurrentLRUCache c) {
+      cache = new WeakReference<ConcurrentLRUCache>(c);
+    }
+
+    public void run() {
+      while (true) {
+        if (stop) break;
+        synchronized (monitor) {
+          try {
+            monitor.wait();
+          } catch (InterruptedException e) {
           }
         }
-      }.start();
+        if (stop) break;
+        ConcurrentLRUCache c = cache.get();
+        if(c == null){
+          break;
+        } else {
+          c.markAndSweep();
+        }
+      }
+
     }
+
+    void notifyThread() {
+      synchronized(monitor){
+        monitor.notify();
+      }
+    }
   }
 
+
   public void setAlive(boolean live) {
     islive = live;
   }
 
-  public Object get(Object key) {
+  public V get(K key) {
     CacheEntry e = map.get(key);
     if (e == null) {
       if (islive) stats.missCounter.incrementAndGet();
@@ -73,16 +108,17 @@
     return e.value;
   }
 
-  public Object remove(Object key) {
+  public V remove(K key) {
     CacheEntry cacheEntry = map.remove(key);
     if (cacheEntry != null) {
       stats.size.decrementAndGet();
+      if(evictionListener != null) evictionListener.evictedEntry(cacheEntry.key , cacheEntry.value);
       return cacheEntry.value;
     }
     return null;
   }
 
-  public Object put(Object key, Object val) {
+  public Object put(K key, V val) {
     if (val == null) return null;
     CacheEntry e = new CacheEntry(key, val, stats.accessCounter.incrementAndGet());
     CacheEntry oldCacheEntry = map.put(key, e);
@@ -112,7 +148,12 @@
             markAndSweep();
           }
         }.start();
-      } else {
+      }
+      if(cleanupThread != null){
+        cleanupThread.notifyThread();
+
+      }
+      if(!newThreadForCleanup && cleanupThread == null) {
         markAndSweep();
       }
     }
@@ -355,18 +396,19 @@
   }
 
 
-  private void evictEntry(Object key) {
-    Object o = map.remove(key);
+  private void evictEntry(K key) {
+    CacheEntry o = map.remove(key);
     if (o == null) return;
     stats.size.decrementAndGet();
     stats.evictionCounter++;
+    if(evictionListener != null) evictionListener.evictedEntry(o.key,o.value);
   }
 
 
   public Map getLatestAccessedItems(long n) {
     // we need to grab the lock since we are changing lastAccessedCopy
     markAndSweepLock.lock();
-    Map result = new LinkedHashMap();
+    Map<K,V> result = new LinkedHashMap<K,V>();
     TreeSet<CacheEntry> tree = new TreeSet<CacheEntry>();
     try {
       for (Map.Entry<Object, CacheEntry> entry : map.entrySet()) {
@@ -402,13 +444,14 @@
     return map;
   }
 
-  private static class CacheEntry implements Comparable<CacheEntry> {
-    Object key, value;
+  private class CacheEntry implements Comparable<CacheEntry> {
+    K key;
+    V value;
     volatile long lastAccessed = 0;
     long lastAccessedCopy = 0;
 
 
-    public CacheEntry(Object key, Object value, long lastAccessed) {
+    public CacheEntry(K key, V value, long lastAccessed) {
       this.key = key;
       this.value = value;
       this.lastAccessed = lastAccessed;
@@ -438,7 +481,10 @@
 
 
   public void destroy() {
-    stop = true;
+    if(cleanupThread != null){
+      cleanupThread.stop = true;
+      cleanupThread.notifyThread();
+    }
   }
 
   public Stats getStats() {
@@ -447,7 +493,6 @@
 
   protected void finalize() throws Throwable {
     destroy();
-    super.finalize();
   }
 
   public static class Stats {
@@ -486,4 +531,7 @@
       return missCounter.get();
     }
   }
+  public static interface EvictionListener<K,V>{
+    public void evictedEntry(K key, V value);
+  }
 }
Index: src/java/org/apache/solr/search/FastLRUCache.java
===================================================================
--- src/java/org/apache/solr/search/FastLRUCache.java	(revision 718169)
+++ src/java/org/apache/solr/search/FastLRUCache.java	(working copy)
@@ -69,15 +69,18 @@
     final int initialSize = str == null ? limit : Integer.parseInt(str);
     str = (String) args.get("autowarmCount");
     autowarmCount = str == null ? 0 : Integer.parseInt(str);
+    str = (String) args.get("cleanupThread");
+    boolean newThread = str == null ? false : Boolean.parseBoolean(str);
     
-    description = "Concurrent LRU Cache(maxSize=" + limit + ", initialSize=" + initialSize + ", minSize="+minLimit + ", acceptableSize="+acceptableLimit;
+    description = "Concurrent LRU Cache(maxSize=" + limit + ", initialSize=" + initialSize +
+            ", minSize="+minLimit + ", acceptableSize="+acceptableLimit+" ,cleanupThread ="+newThread;
     if (autowarmCount > 0) {
       description += ", autowarmCount=" + autowarmCount
               + ", regenerator=" + regenerator;
     }
     description += ')';
 
-    cache = new ConcurrentLRUCache(limit, minLimit, acceptableLimit, initialSize, false, false, -1);
+    cache = new ConcurrentLRUCache(limit, minLimit, acceptableLimit, initialSize, newThread, false, null);
     cache.setAlive(false);
 
     if (persistence == null) {
@@ -153,6 +156,7 @@
 
 
   public void close() {
+    cache.destroy();
   }
 
   //////////////////////// SolrInfoMBeans methods //////////////////////
Index: src/test/org/apache/solr/search/TestFastLRUCache.java
===================================================================
--- src/test/org/apache/solr/search/TestFastLRUCache.java	(revision 714218)
+++ src/test/org/apache/solr/search/TestFastLRUCache.java	(working copy)
@@ -72,7 +72,7 @@
     int upperWaterMark = (int)(lowerWaterMark * 1.1);
 
     Random r = new Random(0);
-    ConcurrentLRUCache cache = new ConcurrentLRUCache(upperWaterMark, lowerWaterMark, (upperWaterMark+lowerWaterMark)/2, upperWaterMark, false, false, 0);
+    ConcurrentLRUCache cache = new ConcurrentLRUCache(upperWaterMark, lowerWaterMark, (upperWaterMark+lowerWaterMark)/2, upperWaterMark, false, false, null);
     boolean getSize=false;
     int minSize=0,maxSize=0;
     for (int i=0; i<iter; i++) {
