jdk/test/java/lang/ref/EarlyTimeout.java
changeset 23027 07b4bf8a9026
child 23702 95c64645aa0b
equal deleted inserted replaced
23026:bdc41bab378b 23027:07b4bf8a9026
       
     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 
       
    37 /**
       
    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.gs().
       
    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  */
       
    46 
       
    47 public class EarlyTimeout extends Thread {
       
    48 
       
    49     static final int THREADS_COUNT = 2;
       
    50     static final int TIMEOUT = 1000;
       
    51 
       
    52     static Object referent = new Object();
       
    53     static final ReferenceQueue<Object> queue = new ReferenceQueue<Object>();
       
    54     static final WeakReference<Object> weakReference = new WeakReference<Object>(referent, queue);
       
    55     static final CountDownLatch startedSignal = new CountDownLatch(THREADS_COUNT);
       
    56 
       
    57     long actual;
       
    58     Reference<?> reference;
       
    59 
       
    60     public static void main(String[] args) throws Exception {
       
    61         EarlyTimeout[] threads = new EarlyTimeout[THREADS_COUNT];
       
    62         for (int i = 0; i < THREADS_COUNT; ++i) {
       
    63             threads[i] = new EarlyTimeout();
       
    64             threads[i].start();
       
    65         }
       
    66         startedSignal.await();
       
    67         referent = null;
       
    68         System.gc();
       
    69         for (EarlyTimeout thread : threads) {
       
    70             thread.join();
       
    71         }
       
    72         if (weakReference.get() != null) {
       
    73             throw new RuntimeException("weakReference was not cleared");
       
    74         }
       
    75         int nonNullRefCount = 0;
       
    76         for (EarlyTimeout thread : threads) {
       
    77             if (thread.reference == null && thread.actual < TIMEOUT) {
       
    78                 throw new RuntimeException("elapsed time " + thread.actual
       
    79                         + " is less than timeout " + TIMEOUT);
       
    80             }
       
    81             if (thread.reference != null && thread.reference == weakReference) {
       
    82                 nonNullRefCount++;
       
    83             }
       
    84         }
       
    85         if (nonNullRefCount != 1) {
       
    86             throw new RuntimeException("more than one references were removed from queue");
       
    87         }
       
    88     }
       
    89 
       
    90     public void run() {
       
    91         try {
       
    92             startedSignal.countDown();
       
    93             long start = System.currentTimeMillis();
       
    94             reference = queue.remove(TIMEOUT);
       
    95             actual = System.currentTimeMillis() - start;
       
    96         } catch (InterruptedException ex) {
       
    97             throw new RuntimeException(ex);
       
    98         }
       
    99     }
       
   100 }