1 /* 2 * Copyright (c) 2014, Oracle and/or its affiliates. All rights reserved. 3 * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER. 4 * 5 * This code is free software; you can redistribute it and/or modify it 6 * under the terms of the GNU General Public License version 2 only, as 7 * published by the Free Software Foundation. 8 * 9 * This code is distributed in the hope that it will be useful, but WITHOUT 10 * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or 11 * FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License 12 * version 2 for more details (a copy is included in the LICENSE file that 13 * accompanied this code). 14 * 15 * You should have received a copy of the GNU General Public License version 16 * 2 along with this work; if not, write to the Free Software Foundation, 17 * Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA. 18 * 19 * Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA 20 * or visit www.oracle.com if you need additional information or have any 21 * questions. 22 */ 23 24 /* @test 25 * @bug 6853696 26 * @summary ReferenceQueue#remove(timeout) should not return null before 27 * timeout is elapsed 28 */ 29 30 import java.lang.InterruptedException; 31 import java.lang.System; 32 import java.lang.ref.Reference; 33 import java.lang.ref.ReferenceQueue; 34 import java.lang.ref.WeakReference; 35 import java.util.concurrent.CountDownLatch; 36 import static java.util.concurrent.TimeUnit.NANOSECONDS; 37 38 /** 39 * In order to demonstrate the issue we make several threads (two appears to be sufficient) 40 * to block in ReferenceQueue#remove(timeout) at the same time. 41 * Then, we force a reference to be enqueued by setting its referent to null and calling System.gc(). 42 * One of the threads gets the reference returned from the remove(). 43 * The other threads get null: 44 * 1) with bug: this may happen before the specified timeout is elapsed, 45 * 2) without bug: this can only happen after the timeout is fully elapsed. 46 */ 47 48 public class EarlyTimeout extends Thread { 49 50 static final int THREADS_COUNT = 2; 51 static final int TIMEOUT = 1000; 52 static final int TOLERANCE = 16; // if elapsed time is less than timeout, and differs from it 53 // by no greater than specified amount, we won't treat it as error 54 55 static Object referent = new Object(); 56 static final ReferenceQueue<Object> queue = new ReferenceQueue<Object>(); 57 static final WeakReference<Object> weakReference = new WeakReference<Object>(referent, queue); 58 static final CountDownLatch startedSignal = new CountDownLatch(THREADS_COUNT); 59 60 long actual; 61 Reference<?> reference; 62 63 public static void main(String[] args) throws Exception { 64 EarlyTimeout[] threads = new EarlyTimeout[THREADS_COUNT]; 65 for (int i = 0; i < THREADS_COUNT; ++i) { 66 threads[i] = new EarlyTimeout(); 67 threads[i].start(); 68 } 69 // The main thread waits until the threads has started and give it a chance 70 // for the threads to block on the queue.remove(TIMEOUT) call 71 startedSignal.await(); 72 Thread.sleep(TIMEOUT / 2); 73 referent = null; 74 System.gc(); 75 for (EarlyTimeout thread : threads) { 76 thread.join(); 77 } 78 if (weakReference.get() != null) { 79 throw new RuntimeException("weakReference was not cleared"); 80 } 81 int nonNullRefCount = 0; 82 for (EarlyTimeout thread : threads) { 83 if (thread.reference == null && thread.actual < TIMEOUT - TOLERANCE) { 84 throw new RuntimeException("elapsed time " + thread.actual 85 + " is less than timeout " + TIMEOUT); 86 } 87 if (thread.reference != null && thread.reference == weakReference) { 88 nonNullRefCount++; 89 } 90 } 91 if (nonNullRefCount > 1) { 92 throw new RuntimeException("more than one references were removed from queue"); 93 } 94 } 95 96 public void run() { 97 try { 98 startedSignal.countDown(); 99 long start = System.nanoTime(); 100 reference = queue.remove(TIMEOUT); 101 actual = NANOSECONDS.toMillis(System.nanoTime() - start); 102 } catch (InterruptedException ex) { 103 throw new RuntimeException(ex); 104 } 105 } 106 }