1*b1cdbd2cSJim Jagielski /**************************************************************
2*b1cdbd2cSJim Jagielski  *
3*b1cdbd2cSJim Jagielski  * Licensed to the Apache Software Foundation (ASF) under one
4*b1cdbd2cSJim Jagielski  * or more contributor license agreements.  See the NOTICE file
5*b1cdbd2cSJim Jagielski  * distributed with this work for additional information
6*b1cdbd2cSJim Jagielski  * regarding copyright ownership.  The ASF licenses this file
7*b1cdbd2cSJim Jagielski  * to you under the Apache License, Version 2.0 (the
8*b1cdbd2cSJim Jagielski  * "License"); you may not use this file except in compliance
9*b1cdbd2cSJim Jagielski  * with the License.  You may obtain a copy of the License at
10*b1cdbd2cSJim Jagielski  *
11*b1cdbd2cSJim Jagielski  *   http://www.apache.org/licenses/LICENSE-2.0
12*b1cdbd2cSJim Jagielski  *
13*b1cdbd2cSJim Jagielski  * Unless required by applicable law or agreed to in writing,
14*b1cdbd2cSJim Jagielski  * software distributed under the License is distributed on an
15*b1cdbd2cSJim Jagielski  * "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY
16*b1cdbd2cSJim Jagielski  * KIND, either express or implied.  See the License for the
17*b1cdbd2cSJim Jagielski  * specific language governing permissions and limitations
18*b1cdbd2cSJim Jagielski  * under the License.
19*b1cdbd2cSJim Jagielski  *
20*b1cdbd2cSJim Jagielski  *************************************************************/
21*b1cdbd2cSJim Jagielski 
22*b1cdbd2cSJim Jagielski 
23*b1cdbd2cSJim Jagielski 
24*b1cdbd2cSJim Jagielski package util;
25*b1cdbd2cSJim Jagielski 
26*b1cdbd2cSJim Jagielski import java.lang.ref.PhantomReference;
27*b1cdbd2cSJim Jagielski import java.lang.ref.ReferenceQueue;
28*b1cdbd2cSJim Jagielski 
29*b1cdbd2cSJim Jagielski /**
30*b1cdbd2cSJim Jagielski  * Wait until an object has become unreachable.
31*b1cdbd2cSJim Jagielski  *
32*b1cdbd2cSJim Jagielski  * <p>Instances of this class will typically be used as either:</p>
33*b1cdbd2cSJim Jagielski  * <pre>
34*b1cdbd2cSJim Jagielski  *   SomeType o = new SomeType(...);
35*b1cdbd2cSJim Jagielski  *   ... // use "o"
36*b1cdbd2cSJim Jagielski  *   WaitUnreachable u = new WaitUnreachable(o);
37*b1cdbd2cSJim Jagielski  *   o = null;
38*b1cdbd2cSJim Jagielski  *   u.waitUnreachable();
39*b1cdbd2cSJim Jagielski  * </pre>
40*b1cdbd2cSJim Jagielski  * <p>or:</p>
41*b1cdbd2cSJim Jagielski  * <pre>
42*b1cdbd2cSJim Jagielski  *   WaitUnreachable u = new WaitUnreachable(new SomeType(...));
43*b1cdbd2cSJim Jagielski  *   ... // use "(SomeType) u.get()"
44*b1cdbd2cSJim Jagielski  *   u.waitUnreachable();
45*b1cdbd2cSJim Jagielski  * </pre>
46*b1cdbd2cSJim Jagielski  */
47*b1cdbd2cSJim Jagielski public final class WaitUnreachable {
48*b1cdbd2cSJim Jagielski     /**
49*b1cdbd2cSJim Jagielski      * Creates a new waiter.
50*b1cdbd2cSJim Jagielski      *
51*b1cdbd2cSJim Jagielski      * @param obj the object on which to wait
52*b1cdbd2cSJim Jagielski      */
WaitUnreachable(Object obj)53*b1cdbd2cSJim Jagielski     public WaitUnreachable(Object obj) {
54*b1cdbd2cSJim Jagielski         this.obj = obj;
55*b1cdbd2cSJim Jagielski         queue = new ReferenceQueue();
56*b1cdbd2cSJim Jagielski         ref = new PhantomReference(obj, queue);
57*b1cdbd2cSJim Jagielski     }
58*b1cdbd2cSJim Jagielski 
59*b1cdbd2cSJim Jagielski     /**
60*b1cdbd2cSJim Jagielski      * Gets the object on which to wait.
61*b1cdbd2cSJim Jagielski      *
62*b1cdbd2cSJim Jagielski      * @return the object on which to wait, or <code>null</code> if
63*b1cdbd2cSJim Jagielski      * <code>waitUnreachable</code> has already been called
64*b1cdbd2cSJim Jagielski      */
get()65*b1cdbd2cSJim Jagielski     public synchronized Object get() {
66*b1cdbd2cSJim Jagielski         return obj;
67*b1cdbd2cSJim Jagielski     }
68*b1cdbd2cSJim Jagielski 
69*b1cdbd2cSJim Jagielski     /**
70*b1cdbd2cSJim Jagielski      * Starts waiting for the object to become unreachable.
71*b1cdbd2cSJim Jagielski      *
72*b1cdbd2cSJim Jagielski      * <p>This blocks the current thread until the object has become
73*b1cdbd2cSJim Jagielski      * unreachable.</p>
74*b1cdbd2cSJim Jagielski      *
75*b1cdbd2cSJim Jagielski      * <p>Actually, this method waits until the JVM has <em>detected</em> that
76*b1cdbd2cSJim Jagielski      * the object has become unreachable.  This is not deterministic, but this
77*b1cdbd2cSJim Jagielski      * methods makes a best effort to cause the JVM to eventually detect the
78*b1cdbd2cSJim Jagielski      * situation.  With a typical JVM, this should suffice.</p>
79*b1cdbd2cSJim Jagielski      */
waitUnreachable()80*b1cdbd2cSJim Jagielski     public void waitUnreachable() {
81*b1cdbd2cSJim Jagielski         synchronized (this) {
82*b1cdbd2cSJim Jagielski             obj = null;
83*b1cdbd2cSJim Jagielski         }
84*b1cdbd2cSJim Jagielski         System.out.println("waiting for gc");
85*b1cdbd2cSJim Jagielski         while (queue.poll() == null) {
86*b1cdbd2cSJim Jagielski             System.gc();
87*b1cdbd2cSJim Jagielski             System.runFinalization();
88*b1cdbd2cSJim Jagielski             byte[] dummy = new byte[1024];
89*b1cdbd2cSJim Jagielski         }
90*b1cdbd2cSJim Jagielski     }
91*b1cdbd2cSJim Jagielski 
92*b1cdbd2cSJim Jagielski     /**
93*b1cdbd2cSJim Jagielski      * Ensures that an object will be finalized as soon as possible.
94*b1cdbd2cSJim Jagielski      *
95*b1cdbd2cSJim Jagielski      * <p>This does not block the current thread.  Instead, a new thread is
96*b1cdbd2cSJim Jagielski      * spawned that busy waits for the given object to become unreachable.</p>
97*b1cdbd2cSJim Jagielski      *
98*b1cdbd2cSJim Jagielski      * <p>This method cannot guarantee that the given object is eventually
99*b1cdbd2cSJim Jagielski      * finalized, but it makes a best effort.  With a typical JVM, this should
100*b1cdbd2cSJim Jagielski      * suffice.</p>
101*b1cdbd2cSJim Jagielski      *
102*b1cdbd2cSJim Jagielski      * @param obj the object of which to ensure finalization
103*b1cdbd2cSJim Jagielski      */
ensureFinalization(final Object obj)104*b1cdbd2cSJim Jagielski     public static void ensureFinalization(final Object obj) {
105*b1cdbd2cSJim Jagielski         final class WaitThread extends Thread {
106*b1cdbd2cSJim Jagielski             public WaitThread(Object obj) {
107*b1cdbd2cSJim Jagielski                 super("ensureFinalization");
108*b1cdbd2cSJim Jagielski                 unreachable = new WaitUnreachable(obj);
109*b1cdbd2cSJim Jagielski             }
110*b1cdbd2cSJim Jagielski 
111*b1cdbd2cSJim Jagielski             public void run() {
112*b1cdbd2cSJim Jagielski                 unreachable.waitUnreachable();
113*b1cdbd2cSJim Jagielski             }
114*b1cdbd2cSJim Jagielski 
115*b1cdbd2cSJim Jagielski             private final WaitUnreachable unreachable;
116*b1cdbd2cSJim Jagielski         }
117*b1cdbd2cSJim Jagielski         new WaitThread(obj).start();
118*b1cdbd2cSJim Jagielski     }
119*b1cdbd2cSJim Jagielski 
120*b1cdbd2cSJim Jagielski     private Object obj;
121*b1cdbd2cSJim Jagielski     private final ReferenceQueue queue;
122*b1cdbd2cSJim Jagielski     private final PhantomReference ref;
123*b1cdbd2cSJim Jagielski }
124