www.pudn.com > GMapViewer-src.zip > ResourcePool.java
package org.sreid.j2me.util;
/**
* Manages shared resources, making sure that each resource is never used by
* more than one client at any given time.
*/
public class ResourcePool {
private final Resource[] pool;
private boolean traceEnabled = false;
/**
* Constructs a ResourcePool to manage the specified resources.
*/
// NOTE: byte[][] is less general, but Dave Morehouse reports that Object[] fails verification on some devices
public ResourcePool(byte[][] resources) {
pool = new Resource[resources.length];
for (int i = 0; i < resources.length; i++) {
pool[i] = new Resource(resources[i]);
}
}
/**
* Calls claimResource, catching InterruptedException.
*/
public Object claimResourceIgnoreInterrupt() {
for (;;) {
try {
return claimResource();
}
catch (InterruptedException e) {
e.printStackTrace();
}
}
}
/**
* Claims a resource, waiting until one is available if necessary. You MUST
* pass the returned resource to releaseResource when you're done with it
* or it will never be made available again. Use try/finally to ensure that
* claimed resources are released.
*/
public synchronized Object claimResource() throws InterruptedException {
for (;;) {
for (int i = 0; i < pool.length; i++) {
Resource r = pool[i];
if (!r.claimed) {
r.claimed = true;
if (traceEnabled) r.trace = new Throwable();
return r.resource;
}
}
// No resources available.
wait();
}
}
/**
* Releases a previously claimed resource.
*/
public synchronized void releaseResource(Object resource) {
for (int i = 0; i < pool.length; i++) {
Resource r = pool[i];
if (r.resource == resource) {
if (!r.claimed) throw new IllegalArgumentException("Tried to release an unclaimed resource: " + resource);
r.claimed = false;
r.trace = null;
notify();
return;
}
}
throw new IllegalArgumentException("Not a known resource: " + resource);
}
/**
* Returns true if claimResource would return without blocking. Be sure to
* synchronize on the ResourcePool instance between calling
* isResourceAvaialble and claimResource, or another thread might claim the
* resource between the two calls.
*/
public synchronized boolean isResourceAvailable() {
for (int i = 0; i < pool.length; i++) {
if (!pool[i].claimed) return true;
}
return false;
}
/**
* Dumps stack traces of when each claimed resource was claimed. This can
* be used for debugging purposes, to locate the source of a resource leak.
* Only works if setTraceEnabled(true) was previously called.
*/
public synchronized void dumpTrace() {
System.err.println("ResourcePool resource claimant trace:");
for (int i = 0; i < pool.length; i++) {
Resource r = pool[i];
if (!r.claimed) System.err.println("(unclaimed)");
else if (r.trace == null) System.err.println("(no trace available)");
else r.trace.printStackTrace();
}
}
/**
* Enables or disables resource claim tracing, as required for dumpTrace.
* Be aware that enabling tracing may have performance implications.
*/
public synchronized void setTraceEnabled(boolean traceEnabled) {
this.traceEnabled = traceEnabled;
}
private static final class Resource {
final Object resource;
boolean claimed = false;
Throwable trace = null; // stack trace from when the resource was claimed
Resource(Object r) {
this.resource = r;
}
}
}