/**
* Copyright (c) 2000-present Liferay, Inc. All rights reserved.
*
* This library is free software; you can redistribute it and/or modify it under
* the terms of the GNU Lesser General Public License as published by the Free
* Software Foundation; either version 2.1 of the License, or (at your option)
* any later version.
*
* This library 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 Lesser General Public License for more
* details.
*/
package com.liferay.portal.kernel.memory;
import com.liferay.portal.kernel.concurrent.ConcurrentIdentityHashMap;
import java.lang.ref.Reference;
import java.lang.ref.ReferenceQueue;
import java.util.Map;
/**
* @author Shuyang Zhou
*/
public class FinalizeManager {
public static final ReferenceFactory PHANTOM_REFERENCE_FACTORY =
new ReferenceFactory() {
@Override
public <T> Reference<T> createReference(
T reference, ReferenceQueue<? super T> referenceQueue) {
return new EqualityPhantomReference<T>(
reference, referenceQueue) {
@Override
public void clear() {
_finalizeActions.remove(this);
super.clear();
}
};
}
};
public static final ReferenceFactory SOFT_REFERENCE_FACTORY =
new ReferenceFactory() {
@Override
public <T> Reference<T> createReference(
T reference, ReferenceQueue<? super T> referenceQueue) {
return new EqualitySoftReference<T>(reference, referenceQueue) {
@Override
public void clear() {
_finalizeActions.remove(this);
super.clear();
}
};
}
};
public static final boolean THREAD_ENABLED = Boolean.getBoolean(
FinalizeManager.class.getName() + ".thread.enabled");
public static final ReferenceFactory WEAK_REFERENCE_FACTORY =
new ReferenceFactory() {
@Override
public <T> Reference<T> createReference(
T reference, ReferenceQueue<? super T> referenceQueue) {
return new EqualityWeakReference<T>(reference, referenceQueue) {
@Override
public void clear() {
_finalizeActions.remove(this);
super.clear();
}
};
}
};
public static <T> Reference<T> register(
T reference, FinalizeAction finalizeAction,
ReferenceFactory referenceFactory) {
Reference<T> newReference = referenceFactory.createReference(
reference, _referenceQueue);
_finalizeActions.put(newReference, finalizeAction);
if (!THREAD_ENABLED) {
_pollingCleanup();
}
return newReference;
}
public interface ReferenceFactory {
public <T> Reference<T> createReference(
T realReference, ReferenceQueue<? super T> referenceQueue);
}
private static void _finalizeReference(
Reference<? extends Object> reference) {
FinalizeAction finalizeAction = _finalizeActions.remove(reference);
if (finalizeAction != null) {
try {
finalizeAction.doFinalize(reference);
}
finally {
reference.clear();
}
}
}
private static void _pollingCleanup() {
Reference<? extends Object> reference = null;
while ((reference = _referenceQueue.poll()) != null) {
_finalizeReference(reference);
}
}
private static final Map<Reference<?>, FinalizeAction> _finalizeActions =
new ConcurrentIdentityHashMap<>();
private static final ReferenceQueue<Object> _referenceQueue =
new ReferenceQueue<>();
private static class FinalizeThread extends Thread {
public FinalizeThread(String name) {
super(name);
}
@Override
public void run() {
while (true) {
try {
_finalizeReference(_referenceQueue.remove());
}
catch (InterruptedException ie) {
}
}
}
}
static {
if (THREAD_ENABLED) {
Thread thread = new FinalizeThread("Finalize Thread");
thread.setContextClassLoader(
FinalizeManager.class.getClassLoader());
thread.setDaemon(true);
thread.start();
}
}
}