8251861: Remove unused jdk.internal.ref.SoftCleanable and WeakCleanable
Reviewed-by: mchung, rriggs
This commit is contained in:
parent
6ed4c89dc8
commit
ba24f9633e
@ -1,5 +1,5 @@
|
|||||||
/*
|
/*
|
||||||
* Copyright (c) 2015, 2016, Oracle and/or its affiliates. All rights reserved.
|
* Copyright (c) 2015, 2020, Oracle and/or its affiliates. All rights reserved.
|
||||||
* DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
|
* DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
|
||||||
*
|
*
|
||||||
* This code is free software; you can redistribute it and/or modify it
|
* This code is free software; you can redistribute it and/or modify it
|
||||||
@ -52,10 +52,6 @@ public final class CleanerImpl implements Runnable {
|
|||||||
*/
|
*/
|
||||||
final PhantomCleanable<?> phantomCleanableList;
|
final PhantomCleanable<?> phantomCleanableList;
|
||||||
|
|
||||||
final WeakCleanable<?> weakCleanableList;
|
|
||||||
|
|
||||||
final SoftCleanable<?> softCleanableList;
|
|
||||||
|
|
||||||
// The ReferenceQueue of pending cleaning actions
|
// The ReferenceQueue of pending cleaning actions
|
||||||
final ReferenceQueue<Object> queue;
|
final ReferenceQueue<Object> queue;
|
||||||
|
|
||||||
@ -87,8 +83,6 @@ public final class CleanerImpl implements Runnable {
|
|||||||
public CleanerImpl() {
|
public CleanerImpl() {
|
||||||
queue = new ReferenceQueue<>();
|
queue = new ReferenceQueue<>();
|
||||||
phantomCleanableList = new PhantomCleanableRef();
|
phantomCleanableList = new PhantomCleanableRef();
|
||||||
weakCleanableList = new WeakCleanableRef();
|
|
||||||
softCleanableList = new SoftCleanableRef();
|
|
||||||
}
|
}
|
||||||
|
|
||||||
/**
|
/**
|
||||||
@ -135,9 +129,7 @@ public final class CleanerImpl implements Runnable {
|
|||||||
InnocuousThread mlThread = (t instanceof InnocuousThread)
|
InnocuousThread mlThread = (t instanceof InnocuousThread)
|
||||||
? (InnocuousThread) t
|
? (InnocuousThread) t
|
||||||
: null;
|
: null;
|
||||||
while (!phantomCleanableList.isListEmpty() ||
|
while (!phantomCleanableList.isListEmpty()) {
|
||||||
!weakCleanableList.isListEmpty() ||
|
|
||||||
!softCleanableList.isListEmpty()) {
|
|
||||||
if (mlThread != null) {
|
if (mlThread != null) {
|
||||||
// Clear the thread locals
|
// Clear the thread locals
|
||||||
mlThread.eraseThreadLocals();
|
mlThread.eraseThreadLocals();
|
||||||
@ -207,109 +199,6 @@ public final class CleanerImpl implements Runnable {
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
/**
|
|
||||||
* Perform cleaning on an unreachable WeakReference.
|
|
||||||
*/
|
|
||||||
public static final class WeakCleanableRef extends WeakCleanable<Object> {
|
|
||||||
private final Runnable action;
|
|
||||||
|
|
||||||
/**
|
|
||||||
* Constructor for a weak cleanable reference.
|
|
||||||
* @param obj the object to monitor
|
|
||||||
* @param cleaner the cleaner
|
|
||||||
* @param action the action Runnable
|
|
||||||
*/
|
|
||||||
WeakCleanableRef(Object obj, Cleaner cleaner, Runnable action) {
|
|
||||||
super(obj, cleaner);
|
|
||||||
this.action = action;
|
|
||||||
}
|
|
||||||
|
|
||||||
/**
|
|
||||||
* Constructor used only for root of weak cleanable list.
|
|
||||||
*/
|
|
||||||
WeakCleanableRef() {
|
|
||||||
super();
|
|
||||||
this.action = null;
|
|
||||||
}
|
|
||||||
|
|
||||||
@Override
|
|
||||||
protected void performCleanup() {
|
|
||||||
action.run();
|
|
||||||
}
|
|
||||||
|
|
||||||
/**
|
|
||||||
* Prevent access to referent even when it is still alive.
|
|
||||||
*
|
|
||||||
* @throws UnsupportedOperationException always
|
|
||||||
*/
|
|
||||||
@Override
|
|
||||||
public Object get() {
|
|
||||||
throw new UnsupportedOperationException("get");
|
|
||||||
}
|
|
||||||
|
|
||||||
/**
|
|
||||||
* Direct clearing of the referent is not supported.
|
|
||||||
*
|
|
||||||
* @throws UnsupportedOperationException always
|
|
||||||
*/
|
|
||||||
@Override
|
|
||||||
public void clear() {
|
|
||||||
throw new UnsupportedOperationException("clear");
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
/**
|
|
||||||
* Perform cleaning on an unreachable SoftReference.
|
|
||||||
*/
|
|
||||||
public static final class SoftCleanableRef extends SoftCleanable<Object> {
|
|
||||||
private final Runnable action;
|
|
||||||
|
|
||||||
/**
|
|
||||||
* Constructor for a soft cleanable reference.
|
|
||||||
* @param obj the object to monitor
|
|
||||||
* @param cleaner the cleaner
|
|
||||||
* @param action the action Runnable
|
|
||||||
*/
|
|
||||||
SoftCleanableRef(Object obj, Cleaner cleaner, Runnable action) {
|
|
||||||
super(obj, cleaner);
|
|
||||||
this.action = action;
|
|
||||||
}
|
|
||||||
|
|
||||||
/**
|
|
||||||
* Constructor used only for root of soft cleanable list.
|
|
||||||
*/
|
|
||||||
SoftCleanableRef() {
|
|
||||||
super();
|
|
||||||
this.action = null;
|
|
||||||
}
|
|
||||||
|
|
||||||
@Override
|
|
||||||
protected void performCleanup() {
|
|
||||||
action.run();
|
|
||||||
}
|
|
||||||
|
|
||||||
/**
|
|
||||||
* Prevent access to referent even when it is still alive.
|
|
||||||
*
|
|
||||||
* @throws UnsupportedOperationException always
|
|
||||||
*/
|
|
||||||
@Override
|
|
||||||
public Object get() {
|
|
||||||
throw new UnsupportedOperationException("get");
|
|
||||||
}
|
|
||||||
|
|
||||||
/**
|
|
||||||
* Direct clearing of the referent is not supported.
|
|
||||||
*
|
|
||||||
* @throws UnsupportedOperationException always
|
|
||||||
*/
|
|
||||||
@Override
|
|
||||||
public void clear() {
|
|
||||||
throw new UnsupportedOperationException("clear");
|
|
||||||
}
|
|
||||||
|
|
||||||
}
|
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* A ThreadFactory for InnocuousThreads.
|
* A ThreadFactory for InnocuousThreads.
|
||||||
* The factory is a singleton.
|
* The factory is a singleton.
|
||||||
|
@ -1,179 +0,0 @@
|
|||||||
/*
|
|
||||||
* Copyright (c) 2015, 2016, Oracle and/or its affiliates. All rights reserved.
|
|
||||||
* DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
|
|
||||||
*
|
|
||||||
* This code is free software; you can redistribute it and/or modify it
|
|
||||||
* under the terms of the GNU General Public License version 2 only, as
|
|
||||||
* published by the Free Software Foundation. Oracle designates this
|
|
||||||
* particular file as subject to the "Classpath" exception as provided
|
|
||||||
* by Oracle in the LICENSE file that accompanied this code.
|
|
||||||
*
|
|
||||||
* This code is distributed in the hope that it will be useful, but WITHOUT
|
|
||||||
* ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
|
|
||||||
* FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License
|
|
||||||
* version 2 for more details (a copy is included in the LICENSE file that
|
|
||||||
* accompanied this code).
|
|
||||||
*
|
|
||||||
* You should have received a copy of the GNU General Public License version
|
|
||||||
* 2 along with this work; if not, write to the Free Software Foundation,
|
|
||||||
* Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA.
|
|
||||||
*
|
|
||||||
* Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA
|
|
||||||
* or visit www.oracle.com if you need additional information or have any
|
|
||||||
* questions.
|
|
||||||
*/
|
|
||||||
|
|
||||||
package jdk.internal.ref;
|
|
||||||
|
|
||||||
import java.lang.ref.Cleaner;
|
|
||||||
import java.lang.ref.Reference;
|
|
||||||
import java.lang.ref.SoftReference;
|
|
||||||
import java.util.Objects;
|
|
||||||
|
|
||||||
/**
|
|
||||||
* SoftCleanable subclasses efficiently encapsulate cleanup state and
|
|
||||||
* the cleaning action.
|
|
||||||
* Subclasses implement the abstract {@link #performCleanup()} method
|
|
||||||
* to provide the cleaning action.
|
|
||||||
* When constructed, the object reference and the {@link Cleaner.Cleanable Cleanable}
|
|
||||||
* are registered with the {@link Cleaner}.
|
|
||||||
* The Cleaner invokes {@link Cleaner.Cleanable#clean() clean} after the
|
|
||||||
* referent becomes softly reachable.
|
|
||||||
*/
|
|
||||||
public abstract class SoftCleanable<T> extends SoftReference<T>
|
|
||||||
implements Cleaner.Cleanable {
|
|
||||||
|
|
||||||
/**
|
|
||||||
* Links to previous and next in a doubly-linked list.
|
|
||||||
*/
|
|
||||||
SoftCleanable<?> prev = this, next = this;
|
|
||||||
|
|
||||||
/**
|
|
||||||
* The list of SoftCleanable; synchronizes insert and remove.
|
|
||||||
*/
|
|
||||||
private final SoftCleanable<?> list;
|
|
||||||
|
|
||||||
/**
|
|
||||||
* Constructs new {@code SoftCleanableReference} with
|
|
||||||
* {@code non-null referent} and {@code non-null cleaner}.
|
|
||||||
* The {@code cleaner} is not retained by this reference; it is only used
|
|
||||||
* to register the newly constructed {@link Cleaner.Cleanable Cleanable}.
|
|
||||||
*
|
|
||||||
* @param referent the referent to track
|
|
||||||
* @param cleaner the {@code Cleaner} to register with
|
|
||||||
*/
|
|
||||||
public SoftCleanable(T referent, Cleaner cleaner) {
|
|
||||||
super(Objects.requireNonNull(referent), CleanerImpl.getCleanerImpl(cleaner).queue);
|
|
||||||
list = CleanerImpl.getCleanerImpl(cleaner).softCleanableList;
|
|
||||||
insert();
|
|
||||||
|
|
||||||
// Ensure referent and cleaner remain accessible
|
|
||||||
Reference.reachabilityFence(referent);
|
|
||||||
Reference.reachabilityFence(cleaner);
|
|
||||||
}
|
|
||||||
|
|
||||||
/**
|
|
||||||
* Construct a new root of the list; not inserted.
|
|
||||||
*/
|
|
||||||
SoftCleanable() {
|
|
||||||
super(null, null);
|
|
||||||
this.list = this;
|
|
||||||
}
|
|
||||||
|
|
||||||
/**
|
|
||||||
* Insert this SoftCleanableReference after the list head.
|
|
||||||
*/
|
|
||||||
private void insert() {
|
|
||||||
synchronized (list) {
|
|
||||||
prev = list;
|
|
||||||
next = list.next;
|
|
||||||
next.prev = this;
|
|
||||||
list.next = this;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
/**
|
|
||||||
* Remove this SoftCleanableReference from the list.
|
|
||||||
*
|
|
||||||
* @return true if Cleanable was removed or false if not because
|
|
||||||
* it had already been removed before
|
|
||||||
*/
|
|
||||||
private boolean remove() {
|
|
||||||
synchronized (list) {
|
|
||||||
if (next != this) {
|
|
||||||
next.prev = prev;
|
|
||||||
prev.next = next;
|
|
||||||
prev = this;
|
|
||||||
next = this;
|
|
||||||
return true;
|
|
||||||
}
|
|
||||||
return false;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
/**
|
|
||||||
* Returns true if the list's next reference refers to itself.
|
|
||||||
*
|
|
||||||
* @return true if the list is empty
|
|
||||||
*/
|
|
||||||
boolean isListEmpty() {
|
|
||||||
synchronized (list) {
|
|
||||||
return list == list.next;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
/**
|
|
||||||
* Unregister this SoftCleanable reference and invoke {@link #performCleanup()},
|
|
||||||
* ensuring at-most-once semantics.
|
|
||||||
*/
|
|
||||||
@Override
|
|
||||||
public final void clean() {
|
|
||||||
if (remove()) {
|
|
||||||
super.clear();
|
|
||||||
performCleanup();
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
/**
|
|
||||||
* Unregister this SoftCleanable and clear the reference.
|
|
||||||
* Due to inherent concurrency, {@link #performCleanup()} may still be invoked.
|
|
||||||
*/
|
|
||||||
@Override
|
|
||||||
public void clear() {
|
|
||||||
if (remove()) {
|
|
||||||
super.clear();
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
/**
|
|
||||||
* The {@code performCleanup} abstract method is overridden
|
|
||||||
* to implement the cleaning logic.
|
|
||||||
* The {@code performCleanup} method should not be called except
|
|
||||||
* by the {@link #clean} method which ensures at most once semantics.
|
|
||||||
*/
|
|
||||||
protected abstract void performCleanup();
|
|
||||||
|
|
||||||
/**
|
|
||||||
* This method always throws {@link UnsupportedOperationException}.
|
|
||||||
* Enqueuing details of {@link Cleaner.Cleanable}
|
|
||||||
* are a private implementation detail.
|
|
||||||
*
|
|
||||||
* @throws UnsupportedOperationException always
|
|
||||||
*/
|
|
||||||
@Override
|
|
||||||
public final boolean isEnqueued() {
|
|
||||||
throw new UnsupportedOperationException("isEnqueued");
|
|
||||||
}
|
|
||||||
|
|
||||||
/**
|
|
||||||
* This method always throws {@link UnsupportedOperationException}.
|
|
||||||
* Enqueuing details of {@link Cleaner.Cleanable}
|
|
||||||
* are a private implementation detail.
|
|
||||||
*
|
|
||||||
* @throws UnsupportedOperationException always
|
|
||||||
*/
|
|
||||||
@Override
|
|
||||||
public final boolean enqueue() {
|
|
||||||
throw new UnsupportedOperationException("enqueue");
|
|
||||||
}
|
|
||||||
}
|
|
@ -1,180 +0,0 @@
|
|||||||
/*
|
|
||||||
* Copyright (c) 2015, 2016, Oracle and/or its affiliates. All rights reserved.
|
|
||||||
* DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
|
|
||||||
*
|
|
||||||
* This code is free software; you can redistribute it and/or modify it
|
|
||||||
* under the terms of the GNU General Public License version 2 only, as
|
|
||||||
* published by the Free Software Foundation. Oracle designates this
|
|
||||||
* particular file as subject to the "Classpath" exception as provided
|
|
||||||
* by Oracle in the LICENSE file that accompanied this code.
|
|
||||||
*
|
|
||||||
* This code is distributed in the hope that it will be useful, but WITHOUT
|
|
||||||
* ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
|
|
||||||
* FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License
|
|
||||||
* version 2 for more details (a copy is included in the LICENSE file that
|
|
||||||
* accompanied this code).
|
|
||||||
*
|
|
||||||
* You should have received a copy of the GNU General Public License version
|
|
||||||
* 2 along with this work; if not, write to the Free Software Foundation,
|
|
||||||
* Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA.
|
|
||||||
*
|
|
||||||
* Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA
|
|
||||||
* or visit www.oracle.com if you need additional information or have any
|
|
||||||
* questions.
|
|
||||||
*/
|
|
||||||
|
|
||||||
package jdk.internal.ref;
|
|
||||||
|
|
||||||
import java.lang.ref.Cleaner;
|
|
||||||
import java.lang.ref.Reference;
|
|
||||||
import java.lang.ref.WeakReference;
|
|
||||||
import java.util.Objects;
|
|
||||||
|
|
||||||
/**
|
|
||||||
* WeakCleanable subclasses efficiently encapsulate cleanup state and
|
|
||||||
* the cleaning action.
|
|
||||||
* Subclasses implement the abstract {@link #performCleanup()} method
|
|
||||||
* to provide the cleaning action.
|
|
||||||
* When constructed, the object reference and the {@link Cleaner.Cleanable Cleanable}
|
|
||||||
* are registered with the {@link Cleaner}.
|
|
||||||
* The Cleaner invokes {@link Cleaner.Cleanable#clean() clean} after the
|
|
||||||
* referent becomes weakly reachable.
|
|
||||||
*/
|
|
||||||
public abstract class WeakCleanable<T> extends WeakReference<T>
|
|
||||||
implements Cleaner.Cleanable {
|
|
||||||
|
|
||||||
/**
|
|
||||||
* Links to previous and next in a doubly-linked list.
|
|
||||||
*/
|
|
||||||
WeakCleanable<?> prev = this, next = this;
|
|
||||||
|
|
||||||
/**
|
|
||||||
* The list of WeakCleanable; synchronizes insert and remove.
|
|
||||||
*/
|
|
||||||
private final WeakCleanable<?> list;
|
|
||||||
|
|
||||||
/**
|
|
||||||
* Constructs new {@code WeakCleanableReference} with
|
|
||||||
* {@code non-null referent} and {@code non-null cleaner}.
|
|
||||||
* The {@code cleaner} is not retained by this reference; it is only used
|
|
||||||
* to register the newly constructed {@link Cleaner.Cleanable Cleanable}.
|
|
||||||
*
|
|
||||||
* @param referent the referent to track
|
|
||||||
* @param cleaner the {@code Cleaner} to register new reference with
|
|
||||||
*/
|
|
||||||
public WeakCleanable(T referent, Cleaner cleaner) {
|
|
||||||
super(Objects.requireNonNull(referent), CleanerImpl.getCleanerImpl(cleaner).queue);
|
|
||||||
list = CleanerImpl.getCleanerImpl(cleaner).weakCleanableList;
|
|
||||||
insert();
|
|
||||||
|
|
||||||
// Ensure referent and cleaner remain accessible
|
|
||||||
Reference.reachabilityFence(referent);
|
|
||||||
Reference.reachabilityFence(cleaner);
|
|
||||||
|
|
||||||
}
|
|
||||||
|
|
||||||
/**
|
|
||||||
* Construct a new root of the list; not inserted.
|
|
||||||
*/
|
|
||||||
WeakCleanable() {
|
|
||||||
super(null, null);
|
|
||||||
this.list = this;
|
|
||||||
}
|
|
||||||
|
|
||||||
/**
|
|
||||||
* Insert this WeakCleanableReference after the list head.
|
|
||||||
*/
|
|
||||||
private void insert() {
|
|
||||||
synchronized (list) {
|
|
||||||
prev = list;
|
|
||||||
next = list.next;
|
|
||||||
next.prev = this;
|
|
||||||
list.next = this;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
/**
|
|
||||||
* Remove this WeakCleanableReference from the list.
|
|
||||||
*
|
|
||||||
* @return true if Cleanable was removed or false if not because
|
|
||||||
* it had already been removed before
|
|
||||||
*/
|
|
||||||
private boolean remove() {
|
|
||||||
synchronized (list) {
|
|
||||||
if (next != this) {
|
|
||||||
next.prev = prev;
|
|
||||||
prev.next = next;
|
|
||||||
prev = this;
|
|
||||||
next = this;
|
|
||||||
return true;
|
|
||||||
}
|
|
||||||
return false;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
/**
|
|
||||||
* Returns true if the list's next reference refers to itself.
|
|
||||||
*
|
|
||||||
* @return true if the list is empty
|
|
||||||
*/
|
|
||||||
boolean isListEmpty() {
|
|
||||||
synchronized (list) {
|
|
||||||
return list == list.next;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
/**
|
|
||||||
* Unregister this WeakCleanable reference and invoke {@link #performCleanup()},
|
|
||||||
* ensuring at-most-once semantics.
|
|
||||||
*/
|
|
||||||
@Override
|
|
||||||
public final void clean() {
|
|
||||||
if (remove()) {
|
|
||||||
super.clear();
|
|
||||||
performCleanup();
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
/**
|
|
||||||
* Unregister this WeakCleanable and clear the reference.
|
|
||||||
* Due to inherent concurrency, {@link #performCleanup()} may still be invoked.
|
|
||||||
*/
|
|
||||||
@Override
|
|
||||||
public void clear() {
|
|
||||||
if (remove()) {
|
|
||||||
super.clear();
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
/**
|
|
||||||
* The {@code performCleanup} abstract method is overridden
|
|
||||||
* to implement the cleaning logic.
|
|
||||||
* The {@code performCleanup} method should not be called except
|
|
||||||
* by the {@link #clean} method which ensures at most once semantics.
|
|
||||||
*/
|
|
||||||
protected abstract void performCleanup();
|
|
||||||
|
|
||||||
/**
|
|
||||||
* This method always throws {@link UnsupportedOperationException}.
|
|
||||||
* Enqueuing details of {@link Cleaner.Cleanable}
|
|
||||||
* are a private implementation detail.
|
|
||||||
*
|
|
||||||
* @throws UnsupportedOperationException always
|
|
||||||
*/
|
|
||||||
@Override
|
|
||||||
public final boolean isEnqueued() {
|
|
||||||
throw new UnsupportedOperationException("isEnqueued");
|
|
||||||
}
|
|
||||||
|
|
||||||
/**
|
|
||||||
* This method always throws {@link UnsupportedOperationException}.
|
|
||||||
* Enqueuing details of {@link Cleaner.Cleanable}
|
|
||||||
* are a private implementation detail.
|
|
||||||
*
|
|
||||||
* @throws UnsupportedOperationException always
|
|
||||||
*/
|
|
||||||
@Override
|
|
||||||
public final boolean enqueue() {
|
|
||||||
throw new UnsupportedOperationException("enqueue");
|
|
||||||
}
|
|
||||||
}
|
|
@ -35,8 +35,6 @@ import java.util.function.Consumer;
|
|||||||
import java.util.function.Supplier;
|
import java.util.function.Supplier;
|
||||||
|
|
||||||
import jdk.internal.ref.PhantomCleanable;
|
import jdk.internal.ref.PhantomCleanable;
|
||||||
import jdk.internal.ref.WeakCleanable;
|
|
||||||
import jdk.internal.ref.SoftCleanable;
|
|
||||||
import jdk.internal.ref.CleanerFactory;
|
import jdk.internal.ref.CleanerFactory;
|
||||||
|
|
||||||
import sun.hotspot.WhiteBox;
|
import sun.hotspot.WhiteBox;
|
||||||
@ -152,20 +150,12 @@ public class CleanerTest {
|
|||||||
void generateCasesInternal(Cleaner cleaner, Consumer<CleanableCase>... runnables) {
|
void generateCasesInternal(Cleaner cleaner, Consumer<CleanableCase>... runnables) {
|
||||||
generateCases(() -> setupPhantomSubclass(cleaner, null),
|
generateCases(() -> setupPhantomSubclass(cleaner, null),
|
||||||
runnables.length, runnables);
|
runnables.length, runnables);
|
||||||
generateCases(() -> setupWeakSubclass(cleaner, null),
|
|
||||||
runnables.length, runnables);
|
|
||||||
generateCases(() -> setupSoftSubclass(cleaner, null),
|
|
||||||
runnables.length, runnables);
|
|
||||||
}
|
}
|
||||||
|
|
||||||
@SuppressWarnings("unchecked")
|
@SuppressWarnings("unchecked")
|
||||||
void generateExceptionCasesInternal(Cleaner cleaner) {
|
void generateExceptionCasesInternal(Cleaner cleaner) {
|
||||||
generateCases(() -> setupPhantomSubclassException(cleaner, null),
|
generateCases(() -> setupPhantomSubclassException(cleaner, null),
|
||||||
1, c -> c.clearRef());
|
1, c -> c.clearRef());
|
||||||
generateCases(() -> setupWeakSubclassException(cleaner, null),
|
|
||||||
1, c -> c.clearRef());
|
|
||||||
generateCases(() -> setupSoftSubclassException(cleaner, null),
|
|
||||||
1, c -> c.clearRef());
|
|
||||||
}
|
}
|
||||||
|
|
||||||
/**
|
/**
|
||||||
@ -346,47 +336,6 @@ public class CleanerTest {
|
|||||||
|
|
||||||
return new CleanableCase(new PhantomReference<>(obj, null), c1, s1);
|
return new CleanableCase(new PhantomReference<>(obj, null), c1, s1);
|
||||||
}
|
}
|
||||||
/**
|
|
||||||
* Create a CleanableCase for a WeakReference.
|
|
||||||
* @param cleaner the cleaner to use
|
|
||||||
* @param obj an object or null to create a new Object
|
|
||||||
* @return a new CleanableCase preset with the object, cleanup, and semaphore
|
|
||||||
*/
|
|
||||||
static CleanableCase setupWeakSubclass(Cleaner cleaner, Object obj) {
|
|
||||||
if (obj == null) {
|
|
||||||
obj = new Object();
|
|
||||||
}
|
|
||||||
Semaphore s1 = new Semaphore(0);
|
|
||||||
|
|
||||||
Cleaner.Cleanable c1 = new WeakCleanable<Object>(obj, cleaner) {
|
|
||||||
protected void performCleanup() {
|
|
||||||
s1.release();
|
|
||||||
}
|
|
||||||
};
|
|
||||||
|
|
||||||
return new CleanableCase(new WeakReference<>(obj, null), c1, s1);
|
|
||||||
}
|
|
||||||
|
|
||||||
/**
|
|
||||||
* Create a CleanableCase for a SoftReference.
|
|
||||||
* @param cleaner the cleaner to use
|
|
||||||
* @param obj an object or null to create a new Object
|
|
||||||
* @return a new CleanableCase preset with the object, cleanup, and semaphore
|
|
||||||
*/
|
|
||||||
static CleanableCase setupSoftSubclass(Cleaner cleaner, Object obj) {
|
|
||||||
if (obj == null) {
|
|
||||||
obj = new Object();
|
|
||||||
}
|
|
||||||
Semaphore s1 = new Semaphore(0);
|
|
||||||
|
|
||||||
Cleaner.Cleanable c1 = new SoftCleanable<Object>(obj, cleaner) {
|
|
||||||
protected void performCleanup() {
|
|
||||||
s1.release();
|
|
||||||
}
|
|
||||||
};
|
|
||||||
|
|
||||||
return new CleanableCase(new SoftReference<>(obj, null), c1, s1);
|
|
||||||
}
|
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Create a CleanableCase for a PhantomReference.
|
* Create a CleanableCase for a PhantomReference.
|
||||||
@ -410,50 +359,6 @@ public class CleanerTest {
|
|||||||
return new CleanableCase(new PhantomReference<>(obj, null), c1, s1, true);
|
return new CleanableCase(new PhantomReference<>(obj, null), c1, s1, true);
|
||||||
}
|
}
|
||||||
|
|
||||||
/**
|
|
||||||
* Create a CleanableCase for a WeakReference.
|
|
||||||
* @param cleaner the cleaner to use
|
|
||||||
* @param obj an object or null to create a new Object
|
|
||||||
* @return a new CleanableCase preset with the object, cleanup, and semaphore
|
|
||||||
*/
|
|
||||||
static CleanableCase setupWeakSubclassException(Cleaner cleaner, Object obj) {
|
|
||||||
if (obj == null) {
|
|
||||||
obj = new Object();
|
|
||||||
}
|
|
||||||
Semaphore s1 = new Semaphore(0);
|
|
||||||
|
|
||||||
Cleaner.Cleanable c1 = new WeakCleanable<Object>(obj, cleaner) {
|
|
||||||
protected void performCleanup() {
|
|
||||||
s1.release();
|
|
||||||
throw new RuntimeException("Exception thrown to cleaner thread");
|
|
||||||
}
|
|
||||||
};
|
|
||||||
|
|
||||||
return new CleanableCase(new WeakReference<>(obj, null), c1, s1, true);
|
|
||||||
}
|
|
||||||
|
|
||||||
/**
|
|
||||||
* Create a CleanableCase for a SoftReference.
|
|
||||||
* @param cleaner the cleaner to use
|
|
||||||
* @param obj an object or null to create a new Object
|
|
||||||
* @return a new CleanableCase preset with the object, cleanup, and semaphore
|
|
||||||
*/
|
|
||||||
static CleanableCase setupSoftSubclassException(Cleaner cleaner, Object obj) {
|
|
||||||
if (obj == null) {
|
|
||||||
obj = new Object();
|
|
||||||
}
|
|
||||||
Semaphore s1 = new Semaphore(0);
|
|
||||||
|
|
||||||
Cleaner.Cleanable c1 = new SoftCleanable<Object>(obj, cleaner) {
|
|
||||||
protected void performCleanup() {
|
|
||||||
s1.release();
|
|
||||||
throw new RuntimeException("Exception thrown to cleaner thread");
|
|
||||||
}
|
|
||||||
};
|
|
||||||
|
|
||||||
return new CleanableCase(new SoftReference<>(obj, null), c1, s1, true);
|
|
||||||
}
|
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* CleanableCase encapsulates the objects used for a test.
|
* CleanableCase encapsulates the objects used for a test.
|
||||||
* The reference to the object is not held directly,
|
* The reference to the object is not held directly,
|
||||||
@ -611,74 +516,6 @@ public class CleanerTest {
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
/**
|
|
||||||
* Example using a Cleaner to remove WeakKey references from a Map.
|
|
||||||
*/
|
|
||||||
@Test
|
|
||||||
void testWeakKey() {
|
|
||||||
ConcurrentHashMap<WeakKey<String>, String> map = new ConcurrentHashMap<>();
|
|
||||||
Cleaner cleaner = Cleaner.create();
|
|
||||||
String key = new String("foo"); // ensure it is not interned
|
|
||||||
String data = "bar";
|
|
||||||
|
|
||||||
map.put(new WeakKey<>(key, cleaner, map), data);
|
|
||||||
|
|
||||||
WeakKey<String> k2 = new WeakKey<>(key, cleaner, map);
|
|
||||||
|
|
||||||
Assert.assertEquals(map.get(k2), data, "value should be found in the map");
|
|
||||||
key = null;
|
|
||||||
System.gc();
|
|
||||||
Assert.assertNotEquals(map.get(k2), data, "value should not be found in the map");
|
|
||||||
|
|
||||||
final long CYCLE_MAX = Utils.adjustTimeout(30L);
|
|
||||||
for (int i = 1; map.size() > 0 && i < CYCLE_MAX; i++) {
|
|
||||||
map.forEach( (k, v) -> System.out.printf(" k: %s, v: %s%n", k, v));
|
|
||||||
try {
|
|
||||||
Thread.sleep(10L);
|
|
||||||
} catch (InterruptedException ie) {}
|
|
||||||
}
|
|
||||||
Assert.assertEquals(map.size(), 0, "Expected map to be empty;");
|
|
||||||
cleaner = null;
|
|
||||||
}
|
|
||||||
|
|
||||||
/**
|
|
||||||
* Test sample class for WeakKeys in Map.
|
|
||||||
* @param <K> A WeakKey of type K
|
|
||||||
*/
|
|
||||||
class WeakKey<K> extends WeakReference<K> {
|
|
||||||
private final int hash;
|
|
||||||
private final ConcurrentHashMap<WeakKey<K>, ?> map;
|
|
||||||
Cleaner.Cleanable cleanable;
|
|
||||||
|
|
||||||
public WeakKey(K key, Cleaner c, ConcurrentHashMap<WeakKey<K>, ?> map) {
|
|
||||||
super(key);
|
|
||||||
this.hash = key.hashCode();
|
|
||||||
this.map = map;
|
|
||||||
cleanable = new WeakCleanable<Object>(key, c) {
|
|
||||||
protected void performCleanup() {
|
|
||||||
map.remove(WeakKey.this);
|
|
||||||
}
|
|
||||||
};
|
|
||||||
}
|
|
||||||
public int hashCode() { return hash; }
|
|
||||||
|
|
||||||
public boolean equals(Object obj) {
|
|
||||||
if (obj == this) {
|
|
||||||
return true;
|
|
||||||
}
|
|
||||||
if (!(obj instanceof WeakKey)) return false;
|
|
||||||
K key = get();
|
|
||||||
if (key == null) return obj == this;
|
|
||||||
return key == ((WeakKey<?>)obj).get();
|
|
||||||
}
|
|
||||||
|
|
||||||
public String toString() {
|
|
||||||
return "WeakKey:" + Objects.toString(get() + ", cleanableRef: " +
|
|
||||||
((Reference)cleanable).get());
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Verify that casting a Cleanup to a Reference is not allowed to
|
* Verify that casting a Cleanup to a Reference is not allowed to
|
||||||
* get the referent or clear the reference.
|
* get the referent or clear the reference.
|
||||||
|
Loading…
x
Reference in New Issue
Block a user