A First Implementation of Pooling

• The resource can be reused many times. • You frequently need more than one instance of the resource because there are many threads that perform tasks involving this type of resource I will call these threads the client threads. The canonical example of a resource that ought to be pooled is a database connection. In Java, database connections are embodied as instances of an implementation of the java.sql.Connection interface. A database vendor will supply a class that implements the Connection interface and is used to communicate with the vendors database server. Database connections almost always involve a socket connection to the database server. Socket connections to the database server are expensive for two reasons. First, the database has a limited number of sockets it can vend. Second, establishing a connection often involves logging into the database and establishing a secure communications channel. Performing the security check is time-consuming and is something you dont want to repeat every time you need to make a query against a database.

12.3.2 Two Interfaces That Define a Pool

Our goal is to define a generic and reusable pooling mechanism. To do so, we start by defining two interfaces: Pool and PoolHelper . These are very simple interfaces, defined in the com.ora.rmibook.chapter12.pool package: public interface Pool{ public Object getObject ; public void returnObjectObject object; } public interface PoolHelper { public Object create ; public boolean disposeObject object; public boolean isObjectStillValidObject object; } Pool and PoolHelper encaspulate everything that the client threads which simply use the pooling mechanism need to know. Pool defines only two methods: getObject lets a client thread get an object from the pool, and returnObject returns an object to the pool thereby making it available for other client threads to use. The second interface helps us build a generic and reusable pool class. Since theres no way an implementation of the Pool interface could know how to construct the objects in the pool, or how to make sure theyre still valid, we need to provide a way for the generic pooling mechanism to create and validate individual objects in the pool. For example, database connections have a tendency to fail over time. The pooling mechanism should occasionally check them and make sure they still work. We build this into our system by defining the PoolHelper interface. Users of the pooling mechanism will implement PoolHelper s three methods in order to customize the pool to their specific needs.

12.3.3 A First Implementation of Pooling

Our first implementation of Pool , called SimplePool , is a basic implementation of Pool . It does the following: • In the constructor, it gets a PoolHelper , a starting size for the pool, and a maximum size. SimplePool immediately creates a set of available objects. The size of the set is the starting size of the pool. • Whenever getObject is called, it checks to see whether it has an object. If it does, it returns one first removing it from the set of available objects. If the pool has no available objects, it calls its helpers create method. • Whenever returnObject is called, the object is put back into the set of available objects if two conditions are met: the set of available objects isnt already at the maximum size e.g., the pool isnt already full, and the object is still valid, which the pool checks by calling the helpers isObjectStillValid method. Heres the code for SimplePool in its entirety: public class SimplePool implements Pool { private int _maximumIndex; private int _currentPosition; private PoolHelper _helper; private Object[] _availableObjects; public SimplePoolint startingSize, int maximumSize, PoolHelper helper { _maximumIndex = maximumSize -1; _helper = helper; buildInitialObjectsstartingSize, maximumSize; } public synchronized Object getObject { if _currentPosition == -1 { return _helper.create ; } return getObjectFromArray ; } private Object getObjectFromArray { Object returnValue = _availableObjects[_currentPosition]; _availableObjects[_currentPosition] = null; _currentPosition--; return returnValue; } public synchronized void returnObjectObject object { if _currentPosition == _maximumIndex { _helper.disposeobject; return; } if _helper.isObjectStillValidobject { _helper.disposeobject; return; } _currentPosition++; _availableObjects[_currentPosition] = object; } private void buildInitialObjectsint startingSize, int maximumSize { _availableObjects = new Object[maximumSize]; int counter; for counter = 0; counter startingSize; counter++ { _availableObjects[counter] =_helper.create ; } _currentPosition = startingSize -1; } }

12.3.4 Problems with SimplePool