The general idea for the Connection Pool pattern is that if instances of a class can be reused, you avoid creating instances of the class by reusing them.
<strong>Reusable</strong>
- Instances of classes in this role collaborate with other objects for a limited amount of time, then they are no longer needed for that collaboration. <strong>Client</strong>
- Instances of classes in this role use Reusable objects. <strong>ReusablePool</strong>
- Instances of classes in this role manage Reusable objects for use by Client objects. Usually, it is desirable to keep all Reusable
objects that are not currently in use in the same object pool so that they can be managed by one coherent policy. To achieve this, the Reusable
Pool class is designed to be a singleton class. Its constructor(s) are private, which forces other classes to call its getInstance method to get the one instance of the ReusablePool
class.
A Client object calls a ReusablePool
object’s acquireReusable
method when it needs a Reusable
object. A ReusablePool
object maintains a collection of Reusable
objects. It uses the collection of Reusable
objects to contain a pool of Reusable
objects that are not currently in use.
If there are any Reusable
objects in the pool when the acquireReusable
method is called, it removes a Reusable
object from the pool and returns it. If the pool is empty, then the acquireReusable
method creates a Reusable
object if it can. If the acquireReusable
method cannot create a new Reusable
object, then it waits until a Reusable
object is returned to the collection.
Client objects pass a Reusable
object to a ReusablePool
object’s releaseReusable
method when they are finished with the object. The releaseReusable
method returns a Reusable
object to the pool of Reusable
objects that are not in use.
In many applications of the Object Pool pattern, there are reasons for limiting the total number of Reusable
objects that may exist. In such cases, the ReusablePool
object that creates Reusable
objects is responsible for not creating more than a specified maximum number of Reusable
objects. If ReusablePool
objects are responsible for limiting the number of objects they will create, then the ReusablePool
class will have a method for specifying the maximum number of objects to be created. That method is indicated in the above diagram as setMaxPoolSize.
Do you like bowling? If you do, you probably know that you should change your shoes when you getting the bowling club. Shoe shelf is wonderful example of Object Pool. Once you want to play, you’ll get your pair (aquireReusable
) from it. After the game, you’ll return shoes back to the shelf (releaseReusable
).
ObjectPool
class with private array of Object
s inside acquare
and release
methods in ObjectPool class // ObjectPool Class
public abstract class ObjectPool<T> { private long expirationTime; private Hashtable<T, Long> locked, unlocked; public ObjectPool() { expirationTime = 30000; // 30 seconds locked = new Hashtable<T, Long>(); unlocked = new Hashtable<T, Long>(); } protected abstract T create(); public abstract boolean validate(T o); public abstract void expire(T o); public synchronized T checkOut() { long now = System.currentTimeMillis(); T t; if (unlocked.size() > 0) { Enumeration<T> e = unlocked.keys(); while (e.hasMoreElements()) { t = e.nextElement(); if ((now - unlocked.get(t)) > expirationTime) { // object has expired unlocked.remove(t); expire(t); t = null; } else { if (validate(t)) { unlocked.remove(t); locked.put(t, now); return (t); } else { // object failed validation unlocked.remove(t); expire(t); t = null; } } } } // no objects available, create a new one t = create(); locked.put(t, now); return (t); } public synchronized void checkIn(T t) { locked.remove(t); unlocked.put(t, System.currentTimeMillis()); } } //The three remaining methods are abstract //and therefore must be implemented by the subclass public class JDBCConnectionPool extends ObjectPool<Connection> { private String dsn, usr, pwd; public JDBCConnectionPool(String driver, String dsn, String usr, String pwd) { super(); try { Class.forName(driver).newInstance(); } catch (Exception e) { e.printStackTrace(); } this.dsn = dsn; this.usr = usr; this.pwd = pwd; } @Override protected Connection create() { try { return (DriverManager.getConnection(dsn, usr, pwd)); } catch (SQLException e) { e.printStackTrace(); return (null); } } @Override public void expire(Connection o) { try { ((Connection) o).close(); } catch (SQLException e) { e.printStackTrace(); } } @Override public boolean validate(Connection o) { try { return (!((Connection) o).isClosed()); } catch (SQLException e) { e.printStackTrace(); return (false); } } }
JDBCConnectionPool will allow the application to borrow and return database connections:
public class Main { public static void main(String args[]) { // Do something... ... // Create the ConnectionPool: JDBCConnectionPool pool = new JDBCConnectionPool( "org.hsqldb.jdbcDriver", "jdbc:hsqldb://localhost/mydb", "sa", "secret"); // Get a connection: Connection con = pool.checkOut(); // Use the connection ... // Return the connection: pool.checkIn(con); } }