The Resource Pool is similar to the implementation of a semaphore. It takes the class type of the resource and number of resource pools associated with it as the constructor parameters. There is a small ambiguity here, when the Resource instance is created it uses reflection, but when we require the resource name a call to getName() from the ResourceA interface is sufficient. Each Resource has a corresponding resource pool entry in the resource_pool_table Map. The poolAvailable Condition variable will signal all waiting threads when a resource is released back into the pool. Correspondingly threads will wait on the Resource Pool lock condition until an object pool is available for the resource with the resourceName. package concurrency;import java.util.Hashtable;import java.util.Vector;import java.util.concurrent.locks.Condition;import java.util.concurrent.locks.Lock;import java.util.concurrent.locks.ReentrantLock;interface ResourceA {    String getName();}interface ResourceExceptionHandler {    void handle(Exception exc);}class ResourceExceptionHandlerImpl implements ResourceExceptionHandler {    @Override    public void handle(Exception exc) {    }}class ResourceCreationException extends Exception {}public class ResourcePool<R extends ResourceA> {    private final Lock lock = new ReentrantLock();    private final Condition poolAvailable = lock.newCondition();    private int num_resource_pools;    private final Hashtable<String, Vector<R>> resource_pool_table = new Hashtable<String, Vector<R>>();    private final Class<R> resourceClass;    private final ResourceExceptionHandler resourceExceptionHandler = new ResourceExceptionHandlerImpl();    private R createResource(String str) {        R resource = null;        try {            resource = resourceClass.getDeclaredConstructor(String.class)                    .newInstance(str);            if (resource == null)                throw new ResourceCreationException();        } catch (Exception e) {            resourceExceptionHandler.handle(e);        }        return resource;    }    public ResourcePool(Class<R> resourceClass, int num_resource_pools) {        lock.lock();        try {            this.resourceClass = resourceClass;            this.num_resource_pools = num_resource_pools;        } finally {            lock.unlock();        }    }    public R acquireResource(String resourceName) throws InterruptedException {        lock.lock();        try {            while (num_resource_pools <= 0)                poolAvailable.await();            --num_resource_pools;            Vector<R> pool = resource_pool_table.get(resourceName);            if (pool != null) {                int size = pool.size();                if (size > 0)                    return pool.remove(size - 1);            }            return createResource(resourceName);        } finally {            lock.unlock();        }    }    public void releaseResource(R resource) {        lock.lock();        try {            String resourceName = resource.getName();            Vector<R> pool = resource_pool_table.get(resourceName);            if (pool == null) {                pool = new Vector<R>();                resource_pool_table.put(resourceName, pool);            }            pool.addElement(resource);            ++num_resource_pools;            poolAvailable.signal();        } finally {            lock.unlock();        }    }}JUnit tests package concurrency;import junit.framework.TestCase;/* * Test Resource  */class SomeResource implements ResourceA {    private String name;    public SomeResource(String name) {        super();        this.name = name;    }    @Override    public String getName() {        return name;    }}/* * Test cases for Resource Pool */public class ResourcePoolTest extends TestCase {  /*Checks the number of the resources in the Resource Table.    Resource is created only if needed.*/    public void testIsEmptyBeforeResourceAcquired() throws Exception {        ResourcePool<SomeResource> resPool = new ResourcePool<SomeResource>(                SomeResource.class, 5);        assertTrue(resPool.isEmpty(A));    } /* Checks if the number of resouces in the Resource Table is equal to the   * maximum number of resources declared at the Resouce Pool creation time.*/       public void testIsFull() throws Exception {        ResourcePool<SomeResource> resPool = new ResourcePool<SomeResource>(                SomeResource.class, 5);        SomeResource[] res = new SomeResource[5];        for (int i = 0; i <= 4; i++) {            res[i] = resPool.acquireResource(A);        }        for (int i = 0; i <= 4; i++) {            resPool.releaseResource(res[i]);        }        assertTrue(resPool.isFull(A));        assertFalse(resPool.isEmpty(A));    }    public  void testAcquireBlocksWhenEmpty() throws Exception {        final ResourcePool<SomeResource> resPool = new ResourcePool<SomeResource>(                SomeResource.class, 0);        Thread resourceConsumer = new Thread() {            public void run() {                try {                    SomeResource unused = resPool.acquireResource(A);                    fail(); // error if control flow reaches this line                } catch (InterruptedException e) {                }            }        };            resourceConsumer.start();            Thread.sleep(1000); // waits for the resourceConsumer to block            resourceConsumer.interrupt();               resourceConsumer.join(1000);    // resume after the resourceConsumer ends            assertFalse(resourceConsumer.isAlive());    }}
Resource Pool implementation with ReentrantLock and Condition
java;locking