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.
|
||||
*
|
||||
* 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 WeakCleanable<?> weakCleanableList;
|
||||
|
||||
final SoftCleanable<?> softCleanableList;
|
||||
|
||||
// The ReferenceQueue of pending cleaning actions
|
||||
final ReferenceQueue<Object> queue;
|
||||
|
||||
@ -87,8 +83,6 @@ public final class CleanerImpl implements Runnable {
|
||||
public CleanerImpl() {
|
||||
queue = new ReferenceQueue<>();
|
||||
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) t
|
||||
: null;
|
||||
while (!phantomCleanableList.isListEmpty() ||
|
||||
!weakCleanableList.isListEmpty() ||
|
||||
!softCleanableList.isListEmpty()) {
|
||||
while (!phantomCleanableList.isListEmpty()) {
|
||||
if (mlThread != null) {
|
||||
// Clear the thread locals
|
||||
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.
|
||||
* 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 jdk.internal.ref.PhantomCleanable;
|
||||
import jdk.internal.ref.WeakCleanable;
|
||||
import jdk.internal.ref.SoftCleanable;
|
||||
import jdk.internal.ref.CleanerFactory;
|
||||
|
||||
import sun.hotspot.WhiteBox;
|
||||
@ -152,20 +150,12 @@ public class CleanerTest {
|
||||
void generateCasesInternal(Cleaner cleaner, Consumer<CleanableCase>... runnables) {
|
||||
generateCases(() -> setupPhantomSubclass(cleaner, null),
|
||||
runnables.length, runnables);
|
||||
generateCases(() -> setupWeakSubclass(cleaner, null),
|
||||
runnables.length, runnables);
|
||||
generateCases(() -> setupSoftSubclass(cleaner, null),
|
||||
runnables.length, runnables);
|
||||
}
|
||||
|
||||
@SuppressWarnings("unchecked")
|
||||
void generateExceptionCasesInternal(Cleaner cleaner) {
|
||||
generateCases(() -> setupPhantomSubclassException(cleaner, null),
|
||||
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);
|
||||
}
|
||||
/**
|
||||
* 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.
|
||||
@ -410,50 +359,6 @@ public class CleanerTest {
|
||||
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.
|
||||
* 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
|
||||
* get the referent or clear the reference.
|
||||
|
Loading…
x
Reference in New Issue
Block a user