Skip to content

Instantly share code, notes, and snippets.

@UnquietCode
Created June 5, 2013 21:51
Show Gist options
  • Save UnquietCode/5717608 to your computer and use it in GitHub Desktop.
Save UnquietCode/5717608 to your computer and use it in GitHub Desktop.
Object pool which reclaims resources not from the user but rather from the garbage collector.
package com.studyblue.utils.pool;
import java.lang.ref.ReferenceQueue;
import java.lang.ref.WeakReference;
import java.util.IdentityHashMap;
import java.util.Map;
import java.util.Queue;
import java.util.concurrent.ArrayBlockingQueue;
import static com.google.common.base.Preconditions.checkArgument;
import static com.google.common.base.Preconditions.checkNotNull;
/**
* Object pool which detects objects about to be garbage collected and returns them
* to the list of available resources. The main use case is detecting resources
* freed by the death of a thread.
*
* @author Ben Fagin
* @version 2013-06-03
*/
public abstract class RecyclingObjectPool<_Resource> {
private final ReferenceQueue<Container<_Resource>> referenceQueue = new ReferenceQueue<Container<_Resource>>();
private final Map<WeakReference, _Resource> referenceMap = new IdentityHashMap<WeakReference, _Resource>();
private final Queue<_Resource> objectQueue;
public RecyclingObjectPool() {
this(15);
}
public RecyclingObjectPool(int capacity) {
checkArgument(capacity > 0);
objectQueue = new ArrayBlockingQueue<_Resource>(capacity);
new Thread() {
public void run() {
while (true) {
try {
WeakReference ref = (WeakReference) referenceQueue.remove();
_Resource resource = referenceMap.remove(ref);
if (resource == null) {
throw new RuntimeException("error: no mapping for resource");
}
objectQueue.offer(resource);
} catch (InterruptedException ex) {
break;
}
}
}
}.start();
}
/*
Get a new resource container.
The trick is to keep a reference to the Container object for as long as you
are using the resource. Once the reference is lost (unreachable), it is marked
for garbage collection. After it is collected, the internal resource is freed
and made available again.
Put another way, if you share the resource object that comes with a {@link Container},
but discard the container, then you will likely end up with two callers using the
same underlying resource object at some point. So don't do it. Treat them as a pair.
*/
public Container<_Resource> get() {
_Resource resource = objectQueue.poll();
if (resource == null) {
resource = checkNotNull(newResource());
}
Container<_Resource> container = new Container<_Resource>(resource);
WeakReference<Container<_Resource>> ref = new WeakReference<Container<_Resource>>(container, referenceQueue);
referenceMap.put(ref, resource);
return container;
}
protected abstract _Resource newResource();
public static class Container<_Resource> {
private final _Resource resource;
private Container(_Resource resource) {
this.resource = resource;
}
public _Resource get() {
return resource;
}
}
}
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment