I've created a database connection pool used on the serverside (of a client-server socket app) and was wondering what improvements can be made to help the design and/or efficiency of the solution. The pool is used from multiple threads so synchronisation is important. The application has been running for a while now with seemingly few problems so the code does appear to work as intended. **Theory:** My basic theory is to have x amount of connections open at any one point in time taking from the top and putting back on the bottom. Connections will only stay alive for so long before they are freed and a new one is created. If I ever have too many because of high server demand a cleanup thread in the *ConnectionPool* class is responsibling for removing the extra connections as required. **Classes** - **ConnectionPool**: Class used to contain the connections and manage their usage - **CachedConnection**: Just a wrapper for Connection and used so that I only keep connections around for a limited time before they are closed and new one takes their place - **DatabaseConnection**: abstract class that holds the connection pool. Children of this class will maintain connection strings etc Some classes not added but used in the code - **EventLog**: Just a logging class, I've actually posted already [here][1] - **WebServer**: A static class to contain some configuration options - **Stopwatch**: Small class that acts as a stopwatch effectively **Code**: public class CachedConnection { private Connection _connection = null; private Stopwatch _stopWatch; private static int KEEP_ALIVE = 1000 * 60 * 20; // 20 minutes max connection life private static long _connectionCounter = 0; private final long _id; public CachedConnection(Connection connection) { _connection = connection; _stopWatch = new Stopwatch(KEEP_ALIVE).start(); _id = newId(); } public Connection getConnection() { return _connection; } public long getId() { return _id; } public boolean keepAlive() { return !_stopWatch.isFinished(); } public void close() throws SQLException { _connection.close(); } private synchronized long newId() { return _connectionCounter++; } } Actual Connection Pool class, the crux of the matter public class ConnectionPool implements Runnable { // Number of initial connections to make. private final int _maxConnections; // A list of available connections for use. private final Queue<CachedConnection> _availableConnections; // A list of connections being used currently. private final Queue<CachedConnection> _usedConnections; // The URL string used to connect to the database private final String m_URLString; // The username used to connect to the database private final String m_UserName; // The password used to connect to the database private final String m_Password; // The cleanup thread private Thread m_CleanupThread = null; //Constructor protected ConnectionPool(String urlString, String user, String passwd, int connections) throws SQLException { // Initialize the required parameters m_URLString = urlString; m_UserName = user; m_Password = passwd; _maxConnections = connections; _usedConnections = new LinkedBlockingQueue<CachedConnection>(); _availableConnections = new LinkedBlockingQueue<CachedConnection>(); setupAvailableConnections(_maxConnections); startCleanUpThread(); } public synchronized void checkin(CachedConnection cached) { if(cached != null) { // Remove from used list. freeConnectionInUse(cached); try { Connection c = cached.getConnection(); if(!c.isClosed()) { // only add it back to our connection pool if we haven't exceeded // the max allowed connections if(availableConnectionCount() < _maxConnections) { addAvailableConnection(cached); } else { closeConnection(cached); } } } catch(SQLException ex) { EventLog.write(ex, "ConnectionPool", "checkin"); } } } public void run() { try { while(true) { int cleanedConnections = 0; while(availableConnectionCount() > _maxConnections) { closeConnection(getNextAvailableConnection()); cleanedConnections++; } if(cleanedConnections > 0) { EventLog.write("Cleaned " + cleanedConnections + " connections", "ConnectionPool", "run"); } // Now sleep for 1 minute Thread.sleep(60000 * 1); } } catch(Exception e) { EventLog.write(e, "ConnectionPool", "run"); } } public CachedConnection checkout() throws SQLException { CachedConnection newConnxn = getNextAvailableConnection(); if(newConnxn != null && newConnxn.keepAlive()) { // Add it to the in use list connectionInUse(newConnxn); } else { // otherwise it's dead so archive it and try and get another instance closeConnection(newConnxn); // add a new available connection newAvailableConnection(); // try to get the first next available connection newConnxn = checkout(); } // Either way, we should have a connection object now. return newConnxn; } private void startCleanUpThread() { // Create the cleanup thread m_CleanupThread = new Thread(this); m_CleanupThread.start(); } private Connection getConnection() throws SQLException { return DriverManager.getConnection(m_URLString, m_UserName, m_Password); } private CachedConnection newCachedConnection() throws SQLException { return new CachedConnection(getConnection()); } private void setupAvailableConnections(int connections) throws SQLException { int counter = 0; while(counter++ < connections) { // Add a new connection to the available list. newAvailableConnection(); } } private synchronized CachedConnection getNextAvailableConnection() { return _availableConnections.poll(); } private synchronized void addAvailableConnection(CachedConnection connection) { _availableConnections.add(connection); } private synchronized void newAvailableConnection() throws SQLException { _availableConnections.add(newCachedConnection()); } private synchronized void connectionInUse(CachedConnection connection) { _usedConnections.add(connection); } private synchronized void freeConnectionInUse(CachedConnection connection) { _usedConnections.remove(connection); } private void closeConnection(CachedConnection c) { if(c != null) { // don't re-add it and the connection is being freed for garbage collection try { c.close(); } catch(SQLException ex) { EventLog.write(ex, "ConnectionPool", "archive"); } finally { int av = availableConnectionCount(); EventLog.write("Closed old connection Id=" + c.getId() + ". Available connections=" + av, "ConnectionPool", "archive"); } } } private synchronized int availableConnectionCount() { return _availableConnections.size(); } } And it's used by children of DatabaseConnection public abstract class DatabaseConnection { private CachedConnection _connection = null; abstract protected ConnectionPool getInstance() throws SQLException; public Connection getConnection() { return _connection.getConnection(); } public boolean isOpen() { return getConnection() != null; } public synchronized void open() throws SQLException { _connection = getInstance().checkout(); } public void close() { if(_connection != null ) { try { getInstance().checkin(_connection); } catch(Exception ex) { EventLog.write(ex.toString(), "DatabaseConnection", "Close" ); } finally { _connection = null; } } else EventLog.write("ERROR: Attempting to close a connection but connection is null", "DatabaseConnection", "close" ); } } And example of a DatabaseConnection child: public class ClientDatabase extends DatabaseConnection { private final String _dbURL; private final String _username = "saywhat"; private final String _password = "noway!"; private final int _connections; private static ConnectionPool _pool = null; public ClientDatabase() { _dbURL = "what you talking about willis"; _connections = WebServer.CONNECTIONS; } @Override protected ConnectionPool getInstance() throws SQLException { if (_pool == null) { synchronized(ClientDatabase.class) { if (_pool == null) _pool = new ConnectionPool(_dbURL, _username, _password, _connections); } } return _pool; } } [1]: http://codereview.stackexchange.com/questions/12336/robust-logging-solution-to-file-on-disk-from-multiple-threads-on-serverside-code