### Question:
ObjectCleaner { public static void register(Object object, Runnable cleanupTask) { AutomaticCleanerReference reference = new AutomaticCleanerReference(object, ObjectUtil.checkNotNull(cleanupTask, "cleanupTask")); LIVE_SET.add(reference); if (CLEANER_RUNNING.compareAndSet(false, true)) { final Thread cleanupThread = new FastThreadLocalThread(CLEANER_TASK); cleanupThread.setPriority(Thread.MIN_PRIORITY); AccessController.doPrivileged(new PrivilegedAction<Void>() { @Override public Void run() { cleanupThread.setContextClassLoader(null); return null; } }); cleanupThread.setName(CLEANER_THREAD_NAME); cleanupThread.setDaemon(true); cleanupThread.start(); } } private  ObjectCleaner(); static void register(Object object, Runnable cleanupTask); static int getLiveSetCount();  }### Answer:
@Test(timeout = 5000) public void testCleanup() throws Exception { final AtomicBoolean freeCalled = new AtomicBoolean(); final CountDownLatch latch = new CountDownLatch(1); temporaryThread = new Thread(new Runnable() { @Override public void run() { try { latch.await(); } catch (InterruptedException ignore) { } } }); temporaryThread.start(); ObjectCleaner.register(temporaryThread, new Runnable() { @Override public void run() { freeCalled.set(true); } }); latch.countDown(); temporaryThread.join(); Assert.assertFalse(freeCalled.get()); temporaryThread = null; while (!freeCalled.get()) { System.gc(); System.runFinalization(); Thread.sleep(100); } }
@Test(timeout = 5000) public void testCleanupContinuesDespiteThrowing() throws InterruptedException { final AtomicInteger freeCalledCount = new AtomicInteger(); final CountDownLatch latch = new CountDownLatch(1); temporaryThread = new Thread(new Runnable() { @Override public void run() { try { latch.await(); } catch (InterruptedException ignore) { } } }); temporaryThread.start(); temporaryObject = new Object(); ObjectCleaner.register(temporaryThread, new Runnable() { @Override public void run() { freeCalledCount.incrementAndGet(); throw new RuntimeException("expected"); } }); ObjectCleaner.register(temporaryObject, new Runnable() { @Override public void run() { freeCalledCount.incrementAndGet(); throw new RuntimeException("expected"); } }); latch.countDown(); temporaryThread.join(); assertEquals(0, freeCalledCount.get()); temporaryThread = null; temporaryObject = null; while (freeCalledCount.get() != 2) { System.gc(); System.runFinalization(); Thread.sleep(100); } }
@Test(timeout = 5000) public void testCleanerThreadIsDaemon() throws Exception { temporaryObject = new Object(); ObjectCleaner.register(temporaryObject, new Runnable() { @Override public void run() { } }); Thread cleanerThread = null; for (Thread thread : Thread.getAllStackTraces().keySet()) { if (thread.getName().equals(ObjectCleaner.CLEANER_THREAD_NAME)) { cleanerThread = thread; break; } } assertNotNull(cleanerThread); assertTrue(cleanerThread.isDaemon()); }