FinalizableReferenceQueueTest.java revision 7dd252788645e940eada959bdde927426e2531c9
1/* 2 * Copyright (C) 2005 The Guava Authors 3 * 4 * Licensed under the Apache License, Version 2.0 (the "License"); 5 * you may not use this file except in compliance with the License. 6 * You may obtain a copy of the License at 7 * 8 * http://www.apache.org/licenses/LICENSE-2.0 9 * 10 * Unless required by applicable law or agreed to in writing, software 11 * distributed under the License is distributed on an "AS IS" BASIS, 12 * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. 13 * See the License for the specific language governing permissions and 14 * limitations under the License. 15 */ 16 17package com.google.common.base; 18 19import com.google.common.base.internal.Finalizer; 20import com.google.common.testing.GcFinalization; 21 22import java.lang.ref.ReferenceQueue; 23import java.lang.ref.WeakReference; 24import java.net.URL; 25import java.net.URLClassLoader; 26 27import junit.framework.TestCase; 28 29/** 30 * Unit test for {@link FinalizableReferenceQueue}. 31 * 32 * @author Bob Lee 33 */ 34public class FinalizableReferenceQueueTest extends TestCase { 35 36 private FinalizableReferenceQueue frq; 37 38 @Override 39 protected void tearDown() throws Exception { 40 frq = null; 41 } 42 43 public void testFinalizeReferentCalled() { 44 final MockReference reference = new MockReference( 45 frq = new FinalizableReferenceQueue()); 46 47 GcFinalization.awaitDone(new GcFinalization.FinalizationPredicate() { 48 @Override 49 public boolean isDone() { 50 return reference.finalizeReferentCalled; 51 } 52 }); 53 } 54 55 static class MockReference extends FinalizableWeakReference<Object> { 56 57 volatile boolean finalizeReferentCalled; 58 59 MockReference(FinalizableReferenceQueue frq) { 60 super(new Object(), frq); 61 } 62 63 @Override 64 public void finalizeReferent() { 65 finalizeReferentCalled = true; 66 } 67 } 68 69 /** 70 * Keeps a weak reference to the underlying reference queue. When this 71 * reference is cleared, we know that the background thread has stopped 72 * and released its strong reference. 73 */ 74 private WeakReference<ReferenceQueue<Object>> queueReference; 75 76 public void testThatFinalizerStops() { 77 weaklyReferenceQueue(); 78 GcFinalization.awaitClear(queueReference); 79 } 80 81 /** 82 * If we don't keep a strong reference to the reference object, it won't 83 * be enqueued. 84 */ 85 FinalizableWeakReference<Object> reference; 86 87 /** 88 * Create the FRQ in a method that goes out of scope so that we're sure 89 * it will be reclaimed. 90 */ 91 private void weaklyReferenceQueue() { 92 frq = new FinalizableReferenceQueue(); 93 queueReference = new WeakReference<ReferenceQueue<Object>>(frq.queue); 94 95 /* 96 * Queue and clear a reference for good measure. We test later on that 97 * the finalizer thread stopped, but we should test that it actually 98 * started first. 99 */ 100 reference = new FinalizableWeakReference<Object>(new Object(), frq) { 101 @Override 102 public void finalizeReferent() { 103 reference = null; 104 frq = null; 105 } 106 }; 107 } 108 109 public void testDecoupledLoader() { 110 FinalizableReferenceQueue.DecoupledLoader decoupledLoader = 111 new FinalizableReferenceQueue.DecoupledLoader() { 112 @Override 113 URLClassLoader newLoader(URL base) { 114 return new DecoupledClassLoader(new URL[] { base }); 115 } 116 }; 117 118 Class<?> finalizerCopy = decoupledLoader.loadFinalizer(); 119 120 assertNotNull(finalizerCopy); 121 assertNotSame(Finalizer.class, finalizerCopy); 122 123 assertNotNull(FinalizableReferenceQueue.getStartFinalizer(finalizerCopy)); 124 } 125 126 static class DecoupledClassLoader extends URLClassLoader { 127 128 public DecoupledClassLoader(URL[] urls) { 129 super(urls); 130 } 131 132 @Override 133 protected synchronized Class<?> loadClass(String name, boolean resolve) 134 throws ClassNotFoundException { 135 // Force Finalizer to load from this class loader, not its parent. 136 if (name.equals(Finalizer.class.getName())) { 137 Class<?> clazz = findClass(name); 138 if (resolve) { 139 resolveClass(clazz); 140 } 141 return clazz; 142 } 143 144 return super.loadClass(name, resolve); 145 } 146 } 147 148 public void testGetFinalizerUrl() { 149 assertNotNull(getClass().getResource("internal/Finalizer.class")); 150 } 151} 152