diff --git a/core/java/src/net/i2p/data/SDSCache.java b/core/java/src/net/i2p/data/SDSCache.java index 8698f6a78b..8902ea1c25 100644 --- a/core/java/src/net/i2p/data/SDSCache.java +++ b/core/java/src/net/i2p/data/SDSCache.java @@ -83,6 +83,18 @@ public class SDSCache { _log.debug("New SDSCache for " + rvClass + " data size: " + len + " max: " + size + " max mem: " + (len * size)); I2PAppContext.getGlobalContext().statManager().createRateStat(_statName, "Hit rate", "Router", new long[] { 10*60*1000 }); + I2PAppContext.getGlobalContext().addShutdownTask(new Shutdown()); + } + + /** + * @since 0.8.8 + */ + private class Shutdown implements Runnable { + public void run() { + synchronized(_cache) { + _cache.clear(); + } + } } /** diff --git a/core/java/src/net/i2p/util/DecayingBloomFilter.java b/core/java/src/net/i2p/util/DecayingBloomFilter.java index ff564b2656..73e4f6523f 100644 --- a/core/java/src/net/i2p/util/DecayingBloomFilter.java +++ b/core/java/src/net/i2p/util/DecayingBloomFilter.java @@ -107,8 +107,18 @@ public class DecayingBloomFilter { context.statManager().createRateStat("router.decayingBloomFilter." + name + ".log10(falsePos)", "log10 of the false positive rate (must have net.i2p.util.DecayingBloomFilter=DEBUG)", "Router", new long[] { Math.max(60*1000, durationMs) }); + context.addShutdownTask(new Shutdown()); } + /** + * @since 0.8.8 + */ + private class Shutdown implements Runnable { + public void run() { + clear(); + } + } + public long getCurrentDuplicateCount() { return _currentDuplicates; } public int getInsertedCount() { diff --git a/core/java/src/net/i2p/util/DecayingHashSet.java b/core/java/src/net/i2p/util/DecayingHashSet.java index f090cf727b..4a10f994e2 100644 --- a/core/java/src/net/i2p/util/DecayingHashSet.java +++ b/core/java/src/net/i2p/util/DecayingHashSet.java @@ -93,8 +93,18 @@ public class DecayingHashSet extends DecayingBloomFilter { "Size", "Router", new long[] { Math.max(60*1000, durationMs) }); context.statManager().createRateStat("router.decayingHashSet." + name + ".dups", "1000000 * Duplicates/Size", "Router", new long[] { Math.max(60*1000, durationMs) }); + context.addShutdownTask(new Shutdown()); } + /** + * @since 0.8.8 + */ + private class Shutdown implements Runnable { + public void run() { + clear(); + } + } + /** unsynchronized but only used for logging elsewhere */ @Override public int getInsertedCount() { diff --git a/core/java/src/net/i2p/util/SimpleScheduler.java b/core/java/src/net/i2p/util/SimpleScheduler.java index 61e2e66b34..728199e658 100644 --- a/core/java/src/net/i2p/util/SimpleScheduler.java +++ b/core/java/src/net/i2p/util/SimpleScheduler.java @@ -2,6 +2,7 @@ package net.i2p.util; import java.util.concurrent.Executors; import java.util.concurrent.ScheduledThreadPoolExecutor; +import java.util.concurrent.ThreadPoolExecutor; import java.util.concurrent.TimeUnit; import java.util.concurrent.ThreadFactory; @@ -48,12 +49,25 @@ public class SimpleScheduler { _threads = (int) Math.max(MIN_THREADS, Math.min(MAX_THREADS, 1 + (maxMemory / (32*1024*1024)))); _executor = new ScheduledThreadPoolExecutor(_threads, new CustomThreadFactory()); _executor.prestartAllCoreThreads(); + // don't bother saving ref to remove hook if somebody else calls stop + _context.addShutdownTask(new Shutdown()); } /** - * Removes the SimpleScheduler. + * @since 0.8.8 + */ + private class Shutdown implements Runnable { + public void run() { + stop(); + } + } + + /** + * Stops the SimpleScheduler. + * Subsequent executions should not throw a RejectedExecutionException. */ public void stop() { + _executor.setRejectedExecutionHandler(new ThreadPoolExecutor.DiscardPolicy()); _executor.shutdownNow(); } diff --git a/core/java/src/net/i2p/util/SimpleTimer.java b/core/java/src/net/i2p/util/SimpleTimer.java index b19b5d691a..ea6069f16f 100644 --- a/core/java/src/net/i2p/util/SimpleTimer.java +++ b/core/java/src/net/i2p/util/SimpleTimer.java @@ -53,16 +53,32 @@ public class SimpleTimer { executor.setDaemon(true); executor.start(); } + _context.addShutdownTask(new Shutdown()); } + /** + * @since 0.8.8 + */ + private class Shutdown implements Runnable { + public void run() { + removeSimpleTimer(); + } + } + /** * Removes the SimpleTimer. */ public void removeSimpleTimer() { synchronized(_events) { runn.setAnswer(false); + _events.clear(); + _eventTimes.clear(); _events.notifyAll(); } + synchronized (_readyEvents) { + _readyEvents.clear(); + _readyEvents.notifyAll(); + } } /** diff --git a/core/java/src/net/i2p/util/SimpleTimer2.java b/core/java/src/net/i2p/util/SimpleTimer2.java index 955f8faa3a..84793c085a 100644 --- a/core/java/src/net/i2p/util/SimpleTimer2.java +++ b/core/java/src/net/i2p/util/SimpleTimer2.java @@ -3,6 +3,7 @@ package net.i2p.util; import java.util.concurrent.Executors; import java.util.concurrent.ScheduledFuture; import java.util.concurrent.ScheduledThreadPoolExecutor; +import java.util.concurrent.ThreadPoolExecutor; import java.util.concurrent.TimeUnit; import java.util.concurrent.ThreadFactory; @@ -48,12 +49,25 @@ public class SimpleTimer2 { _threads = (int) Math.max(MIN_THREADS, Math.min(MAX_THREADS, 1 + (maxMemory / (32*1024*1024)))); _executor = new CustomScheduledThreadPoolExecutor(_threads, new CustomThreadFactory()); _executor.prestartAllCoreThreads(); + // don't bother saving ref to remove hook if somebody else calls stop + _context.addShutdownTask(new Shutdown()); } /** - * Removes the SimpleTimer. + * @since 0.8.8 + */ + private class Shutdown implements Runnable { + public void run() { + stop(); + } + } + + /** + * Stops the SimpleTimer. + * Subsequent executions should not throw a RejectedExecutionException. */ public void stop() { + _executor.setRejectedExecutionHandler(new ThreadPoolExecutor.DiscardPolicy()); _executor.shutdownNow(); }