1 /* 2 * Copyright (c) 2015, 2016, 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. Oracle designates this 8 * particular file as subject to the "Classpath" exception as provided 9 * by Oracle in the LICENSE file that accompanied this code. 10 * 11 * This code is distributed in the hope that it will be useful, but WITHOUT 12 * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or 13 * FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License 14 * version 2 for more details (a copy is included in the LICENSE file that 15 * accompanied this code). 16 * 17 * You should have received a copy of the GNU General Public License version 18 * 2 along with this work; if not, write to the Free Software Foundation, 19 * Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA. 20 * 21 * Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA 22 * or visit www.oracle.com if you need additional information or have any 23 * questions. 24 */ 25 26 package jdk.internal.ref; 27 28 import java.lang.ref.Cleaner; 29 import java.lang.ref.Reference; 30 import java.lang.ref.PhantomReference; 31 import java.util.Objects; 32 33 /** 34 * PhantomCleanable subclasses efficiently encapsulate cleanup state and 35 * the cleaning action. 36 * Subclasses implement the abstract {@link #performCleanup()} method 37 * to provide the cleaning action. 38 * When constructed, the object reference and the {@link Cleaner.Cleanable Cleanable} 39 * are registered with the {@link Cleaner}. 40 * The Cleaner invokes {@link Cleaner.Cleanable#clean() clean} after the 41 * referent becomes phantom reachable. 42 */ 43 public abstract class PhantomCleanable<T> extends PhantomReference<T> 44 implements Cleaner.Cleanable { 45 46 /** 47 * Links to previous and next in a doubly-linked list. 48 */ 49 PhantomCleanable<?> prev = this, next = this; 50 51 /** 52 * The list of PhantomCleanable; synchronizes insert and remove. 53 */ 54 private final PhantomCleanable<?> list; 55 56 /** 57 * Constructs new {@code PhantomCleanable} with 58 * {@code non-null referent} and {@code non-null cleaner}. 59 * The {@code cleaner} is not retained; it is only used to 60 * register the newly constructed {@link Cleaner.Cleanable Cleanable}. 61 * 62 * @param referent the referent to track 63 * @param cleaner the {@code Cleaner} to register with 64 */ PhantomCleanable(T referent, Cleaner cleaner)65 public PhantomCleanable(T referent, Cleaner cleaner) { 66 super(Objects.requireNonNull(referent), CleanerImpl.getCleanerImpl(cleaner).queue); 67 this.list = CleanerImpl.getCleanerImpl(cleaner).phantomCleanableList; 68 insert(); 69 70 // Ensure referent and cleaner remain accessible 71 Reference.reachabilityFence(referent); 72 Reference.reachabilityFence(cleaner); 73 } 74 75 /** 76 * Construct a new root of the list; not inserted. 77 */ PhantomCleanable()78 PhantomCleanable() { 79 super(null, null); 80 this.list = this; 81 } 82 83 /** 84 * Insert this PhantomCleanable after the list head. 85 */ insert()86 private void insert() { 87 synchronized (list) { 88 prev = list; 89 next = list.next; 90 next.prev = this; 91 list.next = this; 92 } 93 } 94 95 /** 96 * Remove this PhantomCleanable from the list. 97 * 98 * @return true if Cleanable was removed or false if not because 99 * it had already been removed before 100 */ remove()101 private boolean remove() { 102 synchronized (list) { 103 if (next != this) { 104 next.prev = prev; 105 prev.next = next; 106 prev = this; 107 next = this; 108 return true; 109 } 110 return false; 111 } 112 } 113 114 /** 115 * Returns true if the list's next reference refers to itself. 116 * 117 * @return true if the list is empty 118 */ isListEmpty()119 boolean isListEmpty() { 120 synchronized (list) { 121 return list == list.next; 122 } 123 } 124 125 /** 126 * Unregister this PhantomCleanable and invoke {@link #performCleanup()}, 127 * ensuring at-most-once semantics. 128 */ 129 @Override clean()130 public final void clean() { 131 if (remove()) { 132 super.clear(); 133 performCleanup(); 134 } 135 } 136 137 /** 138 * Unregister this PhantomCleanable and clear the reference. 139 * Due to inherent concurrency, {@link #performCleanup()} may still be invoked. 140 */ 141 @Override clear()142 public void clear() { 143 if (remove()) { 144 super.clear(); 145 } 146 } 147 148 /** 149 * The {@code performCleanup} abstract method is overridden 150 * to implement the cleaning logic. 151 * The {@code performCleanup} method should not be called except 152 * by the {@link #clean} method which ensures at most once semantics. 153 */ performCleanup()154 protected abstract void performCleanup(); 155 156 /** 157 * This method always throws {@link UnsupportedOperationException}. 158 * Enqueuing details of {@link Cleaner.Cleanable} 159 * are a private implementation detail. 160 * 161 * @throws UnsupportedOperationException always 162 */ 163 @Override isEnqueued()164 public final boolean isEnqueued() { 165 throw new UnsupportedOperationException("isEnqueued"); 166 } 167 168 /** 169 * This method always throws {@link UnsupportedOperationException}. 170 * Enqueuing details of {@link Cleaner.Cleanable} 171 * are a private implementation detail. 172 * 173 * @throws UnsupportedOperationException always 174 */ 175 @Override enqueue()176 public final boolean enqueue() { 177 throw new UnsupportedOperationException("enqueue"); 178 } 179 } 180