Created
June 5, 2013 21:51
-
-
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.
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
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