blob: fc475b2ebddfd8dd530855c8c6c051186ab94611 [file]
/*
* Copyright (c) 2015, 2024, 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.PhantomReference;
import java.util.Objects;
/**
* PhantomCleanable 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 phantom reachable.
*/
public abstract class PhantomCleanable<T> extends PhantomReference<T>
implements Cleaner.Cleanable {
/**
* The list of PhantomCleanable; synchronizes insert and remove.
*/
private final CleanerImpl.CleanableList list;
/**
* Node for this PhantomCleanable in the list.
* Synchronized by the same lock as the list itself.
*/
CleanerImpl.CleanableList.Node node;
/**
* Index of this PhantomCleanable in the list node.
* Synchronized by the same lock as the list itself.
*/
int index;
/**
* Constructs new {@code PhantomCleanable} with
* {@code non-null referent} and {@code non-null cleaner}.
* The {@code cleaner} is not retained; 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
*/
@SuppressWarnings("this-escape")
public PhantomCleanable(T referent, Cleaner cleaner) {
super(Objects.requireNonNull(referent), CleanerImpl.getCleanerImpl(cleaner).queue);
index = -1;
list = CleanerImpl.getCleanerImpl(cleaner).activeList;
list.insert(this);
// Check that list insertion populated the backlinks.
assert node != null;
assert index >= 0;
// Ensure referent and cleaner remain accessible
Reference.reachabilityFence(referent);
Reference.reachabilityFence(cleaner);
}
/**
* Unregister this PhantomCleanable and invoke {@link #performCleanup()},
* ensuring at-most-once semantics.
*/
@Override
public final void clean() {
if (list.remove(this)) {
super.clear();
performCleanup();
}
}
/**
* Unregister this PhantomCleanable and clear the reference.
* Due to inherent concurrency, {@link #performCleanup()} may still be invoked.
*/
@Override
public void clear() {
if (list.remove(this)) {
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
*/
@SuppressWarnings("deprecation")
@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");
}
}