Path: blob/aarch64-shenandoah-jdk8u272-b10/jdk/test/java/lang/ref/EarlyTimeout.java
38812 views
/*1* Copyright (c) 2014, Oracle and/or its affiliates. All rights reserved.2* DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.3*4* This code is free software; you can redistribute it and/or modify it5* under the terms of the GNU General Public License version 2 only, as6* published by the Free Software Foundation.7*8* This code is distributed in the hope that it will be useful, but WITHOUT9* ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or10* FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License11* version 2 for more details (a copy is included in the LICENSE file that12* accompanied this code).13*14* You should have received a copy of the GNU General Public License version15* 2 along with this work; if not, write to the Free Software Foundation,16* Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA.17*18* Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA19* or visit www.oracle.com if you need additional information or have any20* questions.21*/2223/* @test24* @bug 685369625* @summary ReferenceQueue#remove(timeout) should not return null before26* timeout is elapsed27*/2829import java.lang.InterruptedException;30import java.lang.System;31import java.lang.ref.Reference;32import java.lang.ref.ReferenceQueue;33import java.lang.ref.WeakReference;34import java.util.concurrent.CountDownLatch;35import static java.util.concurrent.TimeUnit.NANOSECONDS;3637/**38* In order to demonstrate the issue we make several threads (two appears to be sufficient)39* to block in ReferenceQueue#remove(timeout) at the same time.40* Then, we force a reference to be enqueued by setting its referent to null and calling System.gc().41* One of the threads gets the reference returned from the remove().42* The other threads get null:43* 1) with bug: this may happen before the specified timeout is elapsed,44* 2) without bug: this can only happen after the timeout is fully elapsed.45*/4647public class EarlyTimeout extends Thread {4849static final int THREADS_COUNT = 2;50static final int TIMEOUT = 1000;5152static Object referent = new Object();53static final ReferenceQueue<Object> queue = new ReferenceQueue<Object>();54static final WeakReference<Object> weakReference = new WeakReference<Object>(referent, queue);55static final CountDownLatch startedSignal = new CountDownLatch(THREADS_COUNT);5657long actual;58Reference<?> reference;5960public static void main(String[] args) throws Exception {61EarlyTimeout[] threads = new EarlyTimeout[THREADS_COUNT];62for (int i = 0; i < THREADS_COUNT; ++i) {63threads[i] = new EarlyTimeout();64threads[i].start();65}66// The main thread waits until the threads has started and give it a chance67// for the threads to block on the queue.remove(TIMEOUT) call68startedSignal.await();69Thread.sleep(TIMEOUT / 2);70referent = null;71System.gc();72for (EarlyTimeout thread : threads) {73thread.join();74}75if (weakReference.get() != null) {76throw new RuntimeException("weakReference was not cleared");77}78int nonNullRefCount = 0;79for (EarlyTimeout thread : threads) {80if (thread.reference == null && thread.actual < TIMEOUT) {81throw new RuntimeException("elapsed time " + thread.actual82+ " is less than timeout " + TIMEOUT);83}84if (thread.reference != null && thread.reference == weakReference) {85nonNullRefCount++;86}87}88if (nonNullRefCount > 1) {89throw new RuntimeException("more than one references were removed from queue");90}91}9293public void run() {94try {95startedSignal.countDown();96long start = System.nanoTime();97reference = queue.remove(TIMEOUT);98actual = NANOSECONDS.toMillis(System.nanoTime() - start);99} catch (InterruptedException ex) {100throw new RuntimeException(ex);101}102}103}104105106