/*
 * 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.Cleaner.Cleanable;
import java.lang.ref.ReferenceQueue;
import java.security.AccessController;
import java.security.PrivilegedAction;
import java.util.concurrent.ThreadFactory;
import java.util.concurrent.atomic.AtomicInteger;
import java.util.function.Function;

import jdk.internal.misc.InnocuousThread;

CleanerImpl manages a set of object references and corresponding cleaning actions. CleanerImpl provides the functionality of Cleaner.
/** * CleanerImpl manages a set of object references and corresponding cleaning actions. * CleanerImpl provides the functionality of {@link java.lang.ref.Cleaner}. */
public final class CleanerImpl implements Runnable {
An object to access the CleanerImpl from a Cleaner; set by Cleaner init.
/** * An object to access the CleanerImpl from a Cleaner; set by Cleaner init. */
private static Function<Cleaner, CleanerImpl> cleanerImplAccess = null;
Heads of a CleanableList for each reference type.
/** * Heads of a CleanableList for each reference type. */
final PhantomCleanable<?> phantomCleanableList; final WeakCleanable<?> weakCleanableList; final SoftCleanable<?> softCleanableList; // The ReferenceQueue of pending cleaning actions final ReferenceQueue<Object> queue;
Called by Cleaner static initialization to provide the function to map from Cleaner to CleanerImpl.
Params:
  • access – a function to map from Cleaner to CleanerImpl
/** * Called by Cleaner static initialization to provide the function * to map from Cleaner to CleanerImpl. * @param access a function to map from Cleaner to CleanerImpl */
public static void setCleanerImplAccess(Function<Cleaner, CleanerImpl> access) { if (cleanerImplAccess == null) { cleanerImplAccess = access; } else { throw new InternalError("cleanerImplAccess"); } }
Called to get the CleanerImpl for a Cleaner.
Params:
  • cleaner – the cleaner
Returns:the corresponding CleanerImpl
/** * Called to get the CleanerImpl for a Cleaner. * @param cleaner the cleaner * @return the corresponding CleanerImpl */
static CleanerImpl getCleanerImpl(Cleaner cleaner) { return cleanerImplAccess.apply(cleaner); }
Constructor for CleanerImpl.
/** * Constructor for CleanerImpl. */
public CleanerImpl() { queue = new ReferenceQueue<>(); phantomCleanableList = new PhantomCleanableRef(); weakCleanableList = new WeakCleanableRef(); softCleanableList = new SoftCleanableRef(); }
Starts the Cleaner implementation. Ensure this is the CleanerImpl for the Cleaner. When started waits for Cleanables to be queued.
Params:
  • cleaner – the cleaner
  • threadFactory – the thread factory
/** * Starts the Cleaner implementation. * Ensure this is the CleanerImpl for the Cleaner. * When started waits for Cleanables to be queued. * @param cleaner the cleaner * @param threadFactory the thread factory */
public void start(Cleaner cleaner, ThreadFactory threadFactory) { if (getCleanerImpl(cleaner) != this) { throw new AssertionError("wrong cleaner"); } // schedule a nop cleaning action for the cleaner, so the associated thread // will continue to run at least until the cleaner is reclaimable. new CleanerCleanable(cleaner); if (threadFactory == null) { threadFactory = CleanerImpl.InnocuousThreadFactory.factory(); } // now that there's at least one cleaning action, for the cleaner, // we can start the associated thread, which runs until // all cleaning actions have been run. Thread thread = threadFactory.newThread(this); thread.setDaemon(true); thread.start(); }
Process queued Cleanables as long as the cleanable lists are not empty. A Cleanable is in one of the lists for each Object and for the Cleaner itself. Terminates when the Cleaner is no longer reachable and has been cleaned and there are no more Cleanable instances for which the object is reachable.

If the thread is a ManagedLocalsThread, the threadlocals are erased before each cleanup

/** * Process queued Cleanables as long as the cleanable lists are not empty. * A Cleanable is in one of the lists for each Object and for the Cleaner * itself. * Terminates when the Cleaner is no longer reachable and * has been cleaned and there are no more Cleanable instances * for which the object is reachable. * <p> * If the thread is a ManagedLocalsThread, the threadlocals * are erased before each cleanup */
@Override public void run() { Thread t = Thread.currentThread(); InnocuousThread mlThread = (t instanceof InnocuousThread) ? (InnocuousThread) t : null; while (!phantomCleanableList.isListEmpty() || !weakCleanableList.isListEmpty() || !softCleanableList.isListEmpty()) { if (mlThread != null) { // Clear the thread locals mlThread.eraseThreadLocals(); } try { // Wait for a Ref, with a timeout to avoid getting hung // due to a race with clear/clean Cleanable ref = (Cleanable) queue.remove(60 * 1000L); if (ref != null) { ref.clean(); } } catch (Throwable e) { // ignore exceptions from the cleanup action // (including interruption of cleanup thread) } } }
Perform cleaning on an unreachable PhantomReference.
/** * Perform cleaning on an unreachable PhantomReference. */
public static final class PhantomCleanableRef extends PhantomCleanable<Object> { private final Runnable action;
Constructor for a phantom cleanable reference.
Params:
  • obj – the object to monitor
  • cleaner – the cleaner
  • action – the action Runnable
/** * Constructor for a phantom cleanable reference. * @param obj the object to monitor * @param cleaner the cleaner * @param action the action Runnable */
public PhantomCleanableRef(Object obj, Cleaner cleaner, Runnable action) { super(obj, cleaner); this.action = action; }
Constructor used only for root of phantom cleanable list.
/** * Constructor used only for root of phantom cleanable list. */
PhantomCleanableRef() { super(); this.action = null; } @Override protected void performCleanup() { action.run(); }
Prevent access to referent even when it is still alive.
Throws:
  • UnsupportedOperationException – always
/** * 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
/** * Direct clearing of the referent is not supported. * * @throws UnsupportedOperationException always */
@Override public void clear() { throw new UnsupportedOperationException("clear"); } }
Perform cleaning on an unreachable WeakReference.
/** * Perform cleaning on an unreachable WeakReference. */
public static final class WeakCleanableRef extends WeakCleanable<Object> { private final Runnable action;
Constructor for a weak cleanable reference.
Params:
  • obj – the object to monitor
  • cleaner – the cleaner
  • action – the action Runnable
/** * 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.
/** * 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
/** * 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
/** * 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.
/** * Perform cleaning on an unreachable SoftReference. */
public static final class SoftCleanableRef extends SoftCleanable<Object> { private final Runnable action;
Constructor for a soft cleanable reference.
Params:
  • obj – the object to monitor
  • cleaner – the cleaner
  • action – the action Runnable
/** * 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.
/** * 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
/** * 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
/** * 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.
/** * A ThreadFactory for InnocuousThreads. * The factory is a singleton. */
static final class InnocuousThreadFactory implements ThreadFactory { final static ThreadFactory factory = new InnocuousThreadFactory(); static ThreadFactory factory() { return factory; } final AtomicInteger cleanerThreadNumber = new AtomicInteger(); public Thread newThread(Runnable r) { return AccessController.doPrivileged(new PrivilegedAction<>() { @Override public Thread run() { Thread t = InnocuousThread.newThread(r); t.setPriority(Thread.MAX_PRIORITY - 2); t.setName("Cleaner-" + cleanerThreadNumber.getAndIncrement()); return t; } }); } }
A PhantomCleanable implementation for tracking the Cleaner itself.
/** * A PhantomCleanable implementation for tracking the Cleaner itself. */
static final class CleanerCleanable extends PhantomCleanable<Cleaner> { CleanerCleanable(Cleaner cleaner) { super(cleaner, cleaner); } @Override protected void performCleanup() { // no action } } }