org.codehaus.groovy.util.ReferenceManager Maven / Gradle / Ivy
The newest version!
/*
* Copyright 2003-2010 the original author or authors.
*
* Licensed under the Apache License, Version 2.0 (the "License");
* you may not use this file except in compliance with the License.
* You may obtain a copy of the License at
*
* http://www.apache.org/licenses/LICENSE-2.0
*
* Unless required by applicable law or agreed to in writing, software
* distributed under the License is distributed on an "AS IS" BASIS,
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
* See the License for the specific language governing permissions and
* limitations under the License.
*/
package org.codehaus.groovy.util;
import java.lang.ref.ReferenceQueue;
import java.util.concurrent.atomic.AtomicInteger;
public class ReferenceManager {
private static class ThreadedReferenceManager extends ReferenceManager {
private final Thread thread;
private volatile boolean shouldRun = true;
public ThreadedReferenceManager(ReferenceQueue queue) {
super(queue);
thread = new Thread() {
public void run() {
ReferenceQueue queue = getReferenceQueue();
java.lang.ref.Reference r=null;
while (shouldRun) {
try {
r = queue.remove(1000);
} catch (InterruptedException e) {
break;
}
if (r==null) continue;
if (r instanceof Reference) {
Reference ref = (Reference) r;
Finalizable holder = ref.getHandler();
if (holder!=null) holder.finalizeReference();
}
r.clear();
r=null;
}
}
};
thread.setContextClassLoader(null);
thread.setDaemon(true);
thread.setName(ThreadedReferenceManager.class.getName());
thread.start();
}
@Override
public void stopThread() {
shouldRun = false;
thread.interrupt();
}
@Override
public String toString() {
return "ReferenceManager(threaded, thread="+thread+")";
}
}
public static ReferenceManager createThreadedManager(ReferenceQueue queue) {
return new ThreadedReferenceManager(queue);
}
public static ReferenceManager createIdlingManager(ReferenceQueue queue) {
return new ReferenceManager(queue);
}
public static ReferenceManager createCallBackedManager(ReferenceQueue queue) {
return new ReferenceManager(queue){
@Override
public void removeStallEntries() {
ReferenceQueue queue = getReferenceQueue();
for(;;) {
java.lang.ref.Reference r = queue.poll();
if (r==null) break;
if (r instanceof Reference) {
Reference ref = (Reference) r;
Finalizable holder = ref.getHandler();
if (holder!=null) holder.finalizeReference();
}
r.clear();
r=null;
}
}
@Override
public void afterReferenceCreation(Reference r) {
removeStallEntries();
}
@Override
public String toString() {
return "ReferenceManager(callback)";
}
};
}
public static ReferenceManager createThresholdedIdlingManager(final ReferenceQueue queue, final ReferenceManager callback, final int threshold) {
if (threshold<0) throw new IllegalArgumentException("threshold must not be below 0.");
return new ReferenceManager(queue){
private AtomicInteger refCnt = new AtomicInteger();
private volatile ReferenceManager manager = createIdlingManager(queue);
@Override
public void afterReferenceCreation(Reference r) {
if (manager==callback) {
callback.afterReferenceCreation(r);
return;
}
// we use the idle manager, so let us use the reference counter
// we change the manager once the threshold is reached. There is
// a small chance that the value will go beyond Integer.MAX_VALUE
// so we check for values below 0 too. If threshold is low, then
// this is unlikely to happen. If threshold is high, then we
// have all negative values as fall back
int count = refCnt.incrementAndGet();
if (count>threshold || count<0) {
manager = callback;
}
}
@Override
public String toString() {
return "ReferenceManager(thresholded, current manager="+manager+", threshold="+refCnt.get()+"/"+threshold+")";
}
};
}
private ReferenceQueue queue;
public ReferenceManager(ReferenceQueue queue) {
this.queue = queue;
}
protected ReferenceQueue getReferenceQueue() {
return queue;
}
public void afterReferenceCreation(Reference r) {}
public void removeStallEntries() {}
public void stopThread() {}
@Override
public String toString() {
return "ReferenceManager(idling)";
}
private static final ReferenceBundle SOFT_BUNDLE, WEAK_BUNDLE;
static {
ReferenceQueue queue = new ReferenceQueue();
ReferenceManager callBack = ReferenceManager.createCallBackedManager(queue);
ReferenceManager manager = ReferenceManager.createThresholdedIdlingManager(queue, callBack, 500);
SOFT_BUNDLE = new ReferenceBundle(manager, ReferenceType.SOFT);
WEAK_BUNDLE = new ReferenceBundle(manager, ReferenceType.WEAK);
}
public static ReferenceBundle getDefaultSoftBundle() {
return SOFT_BUNDLE;
}
public static ReferenceBundle getDefaultWeakBundle() {
return WEAK_BUNDLE;
}
}