/** * Return a static / shared {@link WatchdogCache} instance. This instance is backed by the * {@link org.threadly.concurrent.CentralThreadlyPool} which should be fine in most cases, but if * you have specific needs you can construct your own instance by * {@link #WatchdogCache(SubmitterScheduler, boolean)}, or if you need to specify a specific * timeout resolution using the {@link #WatchdogCache(SubmitterScheduler, boolean, long)} * constructor. * <p> * As long as those special cases are not needed, using a shared instance allows for potentially * improved efficiency. * * @since 5.19 * @param sendInterruptOnFutureCancel If {@code true}, and a thread is provided with the future, * an interrupt will be sent on timeout * @return A shared {@link WatchdogCache} with the specified configuration */ public static final WatchdogCache centralWatchdogCache(boolean sendInterruptOnFutureCancel) { AtomicReference<WatchdogCache> ar = sendInterruptOnFutureCancel ? INTERRUPTING_WATCHDOG_CACHE : NONINTERRUPTING_WATCHDOG_CACHE; WatchdogCache wd = ar.get(); if (wd == null) { ar.compareAndSet(null, new WatchdogCache(Watchdog.getStaticScheduler(), sendInterruptOnFutureCancel)); wd = ar.get(); } return wd; }
cachedDogs = new ConcurrentHashMap<>(); watchdogProducer = (timeout) -> { maybeScheduleCleaner(); return new Watchdog(scheduler, timeout, sendInterruptOnFutureCancel); };
@Test public void resolutionTest() { watchdog = new WatchdogCache(scheduler, true); SettableListenableFuture<Object> slf = new SettableListenableFuture<>(); watchdog.watch(slf, WatchdogCache.DEFAULT_RESOLUTION_MILLIS); watchdog.watch(slf, WatchdogCache.DEFAULT_RESOLUTION_MILLIS / 2); watchdog.watch(slf, WatchdogCache.DEFAULT_RESOLUTION_MILLIS / 4); assertEquals(1, watchdog.cachedDogs.size()); watchdog.watch(slf, WatchdogCache.DEFAULT_RESOLUTION_MILLIS + 1); assertEquals(2, watchdog.cachedDogs.size()); } }
@Test public void alreadyDoneFutureWatchTest() { ListenableFuture<Object> future = FutureUtils.immediateResultFuture(null); watchdog.watch(future, TIMEOUT); assertTrue(watchdog.cachedDogs.isEmpty()); }
@Test public void centralWatchdogCacheConstructorTest() { watchdog = WatchdogCache.centralWatchdogCache(true); assertNotNull(watchdog.scheduler); }
@Test public void cacheCleanTest() { SettableListenableFuture<Object> slf = new SettableListenableFuture<>(); watchdog.watch(slf, TIMEOUT); assertFalse(watchdog.cachedDogs.isEmpty()); TestUtils.blockTillClockAdvances(); assertEquals(2, scheduler.advance(WatchdogCache.INSPECTION_INTERVAL_MILLIS)); assertTrue(watchdog.cachedDogs.isEmpty()); }
/** * Return a static / shared {@link WatchdogCache} instance. This instance is backed by the * {@link org.threadly.concurrent.CentralThreadlyPool} which should be fine in most cases, but if * you have specific needs you can construct your own instance by * {@link #WatchdogCache(SubmitterScheduler, boolean)}, or if you need to specify a specific * timeout resolution using the {@link #WatchdogCache(SubmitterScheduler, boolean, long)} * constructor. * <p> * As long as those special cases are not needed, using a shared instance allows for potentially * improved efficiency. * * @since 5.19 * @param sendInterruptOnFutureCancel If {@code true}, and a thread is provided with the future, * an interrupt will be sent on timeout * @return A shared {@link WatchdogCache} with the specified configuration */ public static final WatchdogCache centralWatchdogCache(boolean sendInterruptOnFutureCancel) { AtomicReference<WatchdogCache> ar = sendInterruptOnFutureCancel ? INTERRUPTING_WATCHDOG_CACHE : NONINTERRUPTING_WATCHDOG_CACHE; WatchdogCache wd = ar.get(); if (wd == null) { ar.compareAndSet(null, new WatchdogCache(Watchdog.getStaticScheduler(), sendInterruptOnFutureCancel)); wd = ar.get(); } return wd; }
cachedDogs = new ConcurrentHashMap<>(); watchdogProducer = (timeout) -> { maybeScheduleCleaner(); return new Watchdog(scheduler, timeout, sendInterruptOnFutureCancel); };
@Test public void expiredFutureTest() { SettableListenableFuture<Object> slf = new SettableListenableFuture<>(); watchdog.watch(slf, TIMEOUT); TestUtils.blockTillClockAdvances(); assertEquals(1, scheduler.tick()); assertTrue(slf.isCancelled()); }
@Test @SuppressWarnings("deprecation") public void booleanSchedulerConstructorTest() { watchdog = new WatchdogCache(true); assertNotNull(watchdog.scheduler); }
@Before public void setup() { scheduler = new TestableScheduler(); watchdog = new WatchdogCache(scheduler, true, 1); }