Connection Pool

Olá,

Será que alguém tem algum código de implementação de Connection Pool usando o JDBC. O meu banco de dados é Oracle.

:roll:

Obrigada.

[quote=“vansol”]Olá,

Será que alguém tem algum código de implementação de Connection Pool usando o JDBC. O meu banco de dados é Oracle.

:roll:

Obrigada.[/quote]

c vc tiver falando dos drivers…

aki ta o link

http://otn.oracle.com/software/tech/java/sqlj_jdbc/index.html

agora se vc quer exemplos de jdbc… tenta ler o anuncio q tem na secção JDBC/SQL

Olá, Vansol

Tenho uma connection pool que desenvolvi para o MySQL. Tente adaptá-la para o Oracle.

Lembre-se. Este código foi desenvovido por mim e tenho usado normalmente. Porém, ele nunca passou pelo crivo de outro programador. Portanto, por favor, não o use para algum projeto espacial, de UTI ou coisa parecida. :slight_smile:

Se alguém usar este código, eu apreciaria um feedback.

package hipersoft.telensino;

import java.io.IOException;
import java.sql.CallableStatement;
import java.sql.DatabaseMetaData;
import java.sql.DriverManager;
import java.sql.PreparedStatement;
import java.sql.SQLException;
import java.sql.SQLWarning;
import java.sql.Savepoint;
import java.sql.Statement;
import java.util.Map;
import java.util.Vector;

/**
 * Implementa uma pool de conexões ao servidor SQL.
 * Esta classe foi construída 'from the scratch'.
 *
 * @author Alexandre Furtado Neto
 */
public class ConnectionPool
{
  private Vector livres = new Vector();  // cache da pool
  private int ativas;
  private PoolConfig config;

  /**
   * Constrói um pool. Deve ser chamado após o arquivo de configuração ser aberto.
   *
   * @param config referência para a aplicação
   */
  public ConnectionPool(PoolConfig config)
  {
    this.config = config;
    try
    {
      // carrega o driver apropriado
      //
      Class.forName(config.getDb_driver()).newInstance();
    }
    catch(Throwable e)
    {
      // qualquer exceção neste momento é fatal
      //
      System.out.println(e);
      System.exit(1);
    }
  }

  /**
   * Obtém uma conexão deste pool.
   */
  public synchronized Connection getConnection() throws IOException
  {
    java.sql.Connection con = null;
    //
    // varre o pool à procura de uma conexão livre
    //
    while(livres.size() > 0)
    {
      con = (Connection) livres.firstElement();
      livres.removeElementAt(0);
      try
      {
        // a conexão já foi encerrada pelo DBMS?
        //
        if(!con.isClosed())
        {
          con.getMetaData();            // acorda a conexão (reinicia o timeout)
          break;
        }
      }
      catch(SQLException e) {}          // conexão bichada, ignora e tenta outra
      config.getContext().log("bad connection removed");
      con = null;
    }
    //
    // se for preciso, cria uma nova conexão
    //
    if(con == null)
    {
      try
      {
        con = novaConexao();
      }
      catch(SQLException e)
      {
        throw new IOException(e.toString());
      }
    }
    //
    // atualiza contador e fabrica a conexão final
    //
    ativas++;
    return new Connection(this, con);
  }

  /**
   * Obtém o número de conexões ativas na pool. Seu uso previsto é para alimentar um
   * mostrador no painel de administração.
   *
   * @return int contendo o número de conexões
   */
  public int getAtivas()
  {
    return ativas;
  }

  /**
   * Obtém o número de conexões livres na pool. Seu uso previsto é para alimentar um
   * mostrador no painel de administração.
   *
   * @return o número de conexões livres
   */
  public int getLivres()
  {
    return livres.size();
  }

  /*
   * Cria uma nova conexão.
   */
  private java.sql.Connection novaConexao() throws SQLException
  {
    java.sql.Connection con = DriverManager.getConnection(
	  config.getDb_url(), config.getDb_user(), config.getDb_pass());
    config.getContext().log("criada nova conexao");
    return con;
  }

  /*
   * Devolve a conexão ao pool.
   */
  public synchronized void devolve(Connection con) throws SQLException
  {
    // se o pool estiver cheio, fecha a conexão
    //
    if(livres.size() < config.getPOOL())
      livres.addElement(con);
    else
      con.close();
    //
    ativas--;
    if(ativas < 0)
      config.getContext().log("Exceção não-fatal: número de conexões tornou-se negativo: " + ativas);
  }

  /**
   * Libera todos os recursos da pool. Deve ser invocado quando a aplicação fechar.
   */
  public synchronized void release() throws SQLException
  {
    for(int i = 0; i < livres.size(); i++)
    {
      Connection con = (Connection) livres.elementAt(i);
      con.close();
    }
    livres.removeAllElements();
  }
}

/**
 * Veste uma conexão java.sql para evitar que o método close seja
 * chamado diretamente.
 */
class Connection implements java.sql.Connection
{
  private java.sql.Connection con;
  ConnectionPool pool;

  /**
   * Construtor.
   */
  Connection(ConnectionPool pool, java.sql.Connection con) throws IOException
  {
    this.pool = pool;
    this.con = con;
    if(con == null)
      throw new IOException("parâmetro con null");
  }

  ///////////////// da interface Connection ///////////////////////

  /**
   * Implementa método de mesmo nome na interface <I>java.sql.Connection</I>.
   */
  public void clearWarnings() throws SQLException
  {
    con.clearWarnings();
  }

  /**
   * Implementa método de mesmo nome na interface <I>java.sql.Connection</I>.
   */
  public void close() throws SQLException
  {
    pool.devolve(this);
  }

  /**
   * Implementa método de mesmo nome na interface <I>java.sql.Connection</I>.
   */
  public void commit() throws SQLException
  {
    con.commit();
  }

  /**
   * Implementa método de mesmo nome na interface <I>java.sql.Connection</I>.
   */
  public Statement createStatement() throws SQLException
  {
    return con.createStatement();
  }

  /**
   * Implementa método de mesmo nome na interface <I>java.sql.Connection</I>.
   */
  public Statement createStatement(int resultSetType, int resultSetConcurrency)
    throws SQLException
  {
    return con.createStatement(resultSetType, resultSetConcurrency);
  }

  /**
   * Implementa método de mesmo nome na interface <I>java.sql.Connection</I>.
   */
  public Statement createStatement(int resultSetType,
                                   int resultSetConcurrency,
                                   int resultSetHoldability) throws SQLException
  {
    return con.createStatement(resultSetType, resultSetConcurrency, resultSetHoldability);
  }

  /**
   * Implementa método de mesmo nome na interface <I>java.sql.Connection</I>.
   */
  public boolean getAutoCommit() throws SQLException
  {
    return con.getAutoCommit();
  }

  /**
   * Implementa método de mesmo nome na interface <I>java.sql.Connection</I>.
   */
  public String getCatalog() throws SQLException
  {
    return con.getCatalog();
  }

  /**
   * Implementa método de mesmo nome na interface <I>java.sql.Connection</I>.
   */
  public DatabaseMetaData getMetaData() throws SQLException
  {
    return con.getMetaData();
  }

  /**
   * Implementa método de mesmo nome na interface <I>java.sql.Connection</I>.
   */
  public int getTransactionIsolation() throws SQLException
  {
    return con.getTransactionIsolation();
  }

  /**
   * Implementa método de mesmo nome na interface <I>java.sql.Connection</I>.
   */
  public Map getTypeMap() throws SQLException
  {
    return con.getTypeMap();
  }

  /**
   * Implementa método de mesmo nome na interface <I>java.sql.Connection</I>.
   */
  public SQLWarning getWarnings() throws SQLException
  {
    return con.getWarnings();
  }

  /**
   * Implementa método de mesmo nome na interface <I>java.sql.Connection</I>.
   */
  public boolean isClosed() throws SQLException
  {
    if(con == null)
      return false;
    return con.isClosed();
  }

  /**
   * Implementa método de mesmo nome na interface <I>java.sql.Connection</I>.
   */
  public boolean isReadOnly() throws SQLException
  {
    return con.isReadOnly();
  }

  /**
   * Implementa método de mesmo nome na interface <I>java.sql.Connection</I>.
   */
  public String nativeSQL(String sql) throws SQLException
  {
    return con.nativeSQL(sql);
  }

  /**
   * Implementa método de mesmo nome na interface <I>java.sql.Connection</I>.
   */
  public CallableStatement prepareCall(String sql) throws SQLException
  {
    return con.prepareCall(sql);
  }

  /**
   * Implementa método de mesmo nome na interface <I>java.sql.Connection</I>.
   */
  public CallableStatement prepareCall(String sql, int resultSetType, int resultSetConcurrency)
    throws SQLException
  {
    return con.prepareCall(sql, resultSetType, resultSetConcurrency);
  }

  /**
   * Implementa método de mesmo nome na interface <I>java.sql.Connection</I>.
   */
  public CallableStatement prepareCall(String sql,
                                       int resultSetType,
                                       int resultSetConcurrency,
                                       int resultSetHoldability) throws SQLException
  {
    return con.prepareCall(sql, resultSetType, resultSetConcurrency, resultSetHoldability);
  }

  /**
   * Implementa método de mesmo nome na interface <I>java.sql.Connection</I>.
   */
  public PreparedStatement prepareStatement(String sql) throws SQLException
  {
    return con.prepareStatement(sql);
  }

  /**
   * Implementa método de mesmo nome na interface <I>java.sql.Connection</I>.
   */
  public PreparedStatement prepareStatement(String sql, int autoGeneratedKeys)
    throws SQLException
  {
    return con.prepareStatement(sql, autoGeneratedKeys);
  }

  /**
   * Implementa método de mesmo nome na interface <I>java.sql.Connection</I>.
   */
  public PreparedStatement prepareStatement(
    String sql, int resultSetType, int resultSetConcurrency) throws SQLException
  {
    return con.prepareStatement(sql, resultSetType, resultSetConcurrency);
  }

  /**
   * Implementa método de mesmo nome na interface <I>java.sql.Connection</I>.
   */
  public PreparedStatement prepareStatement(String sql, int[] columnIndexes)
    throws SQLException
  {
    return con.prepareStatement(sql, columnIndexes);
  }

  /**
   * Implementa método de mesmo nome na interface <I>java.sql.Connection</I>.
   */
  public PreparedStatement prepareStatement(String sql, String[] columnNames)
    throws SQLException
  {
    return con.prepareStatement(sql, columnNames);
  }

  /**
   * Implementa método de mesmo nome na interface <I>java.sql.Connection</I>.
   */
  public PreparedStatement prepareStatement(String sql,
                                            int resultSetType,
                                            int resultSetConcurrency,
                                            int resultSetHoldability) throws SQLException
  {
    return con.prepareStatement(sql, resultSetType, resultSetConcurrency, resultSetHoldability);
  }

  /**
   * Implementa método de mesmo nome na interface <I>java.sql.Connection</I>.
   */
  public void releaseSavepoint(Savepoint savepoint) throws SQLException
  {
    con.releaseSavepoint(savepoint);
  }

  /**
   * Implementa método de mesmo nome na interface <I>java.sql.Connection</I>.
   */
  public void rollback() throws SQLException
  {
    con.rollback();
  }

  /**
   * Implementa método de mesmo nome na interface <I>java.sql.Connection</I>.
   */
  public void rollback(Savepoint savepoint) throws SQLException
  {
    con.rollback(savepoint);
  }

  /**
   * Implementa método de mesmo nome na interface <I>java.sql.Connection</I>.
   */
  public void setAutoCommit(boolean autocommit) throws SQLException
  {
    con.setAutoCommit(autocommit);
  }

  /**
   * Implementa método de mesmo nome na interface <I>java.sql.Connection</I>.
   */
  public void setCatalog(String catalog) throws SQLException
  {
    con.setCatalog(catalog);
  }

  /**
   * Implementa método de mesmo nome na interface <I>java.sql.Connection</I>.
   */
  public void setReadOnly(boolean readOnly) throws SQLException
  {
    con.setReadOnly(readOnly);
  }

  /**
   * Implementa método de mesmo nome na interface <I>java.sql.Connection</I>.
   */
  public void setTransactionIsolation(int level) throws SQLException
  {
    con.setTransactionIsolation(level);
  }

  /**
   * Implementa método de mesmo nome na interface <I>java.sql.Connection</I>.
   */
  public void setTypeMap(Map map) throws SQLException
  {
    con.setTypeMap(map);
  }

  /**
   * Implementa método de mesmo nome na interface <I>java.sql.Connection</I>.
   */
  public void setHoldability(int a) throws SQLException
  {
    con.setHoldability(a);
  }

  /**
   * Implementa método de mesmo nome na interface <I>java.sql.Connection</I>.
   */
  public int getHoldability() throws SQLException
  {
    return con.getHoldability();
  }

  /**
   * Implementa método de mesmo nome na interface <I>java.sql.Connection</I>.
   */
  public Savepoint setSavepoint() throws SQLException
  {
    return con.setSavepoint();
  }

  /**
   * Implementa método de mesmo nome na interface <I>java.sql.Connection</I>.
   */
  public Savepoint setSavepoint(String name) throws SQLException
  {
    return con.setSavepoint(name);
  }
}

Olá Alexandre, estou verificando seu código e percebi que está faltando a classe PoolConfig. Vc pode envia-la para que eu possa testar esta solução?

grato.

henrique.

Implementei o meu Connection Pool:

http://pedroabs.wordpress.com/2011/09/27/connection-pool-em-java-pool-de-conexoes/

Muito inteligente sua implementação.

Parabens aos pedroabs e ao hipersoftPJ!
Muito boas as idéias.

Penso em adaptar um pouco o codigo do pedroabs para criar um singleton da classe ConnectionPool e penso também em extende-la de Thread para que a propria classe se encarrege das concorrencias.

Quais os possiveis problemas que eu possa esbarrar fazendo isso?
Alguem mais tem estudado esta forma de Pooling?

Obrigado de seu elogio caro colega Luiz. Peço para que se atente que desenvolvi este artefato com o objetivo de utilizá-lo em Servlets (que já são multithread por natureza). Para utilizá-lo em outro tipo de aplicação (swing, etc …) há realmente a necessidade de adaptá-lo para que funcione com várias Threads.

Pensei nesta outra forma para fazer o Pool de conexões

Interface reponsável pelos atributos básicos da conexão

[code]
package PoolJDBC;

/**
*

  • @author Luiz Augusto Prado
  • www.codigorapido.com.br
    */
    public interface ConnectionInterface
    {
    String getDriver();
    String getUrl();
    String getUser();
    String getPass();
    int getMinOfConnections();
    int getMaxOfConnections();
    int getTimeToStandConnections();
    }[/code]
    ConnectionDB implementa Connection
package PoolJDBC;
import java.sql.Array;
import java.sql.Blob;
import java.sql.CallableStatement;
import java.sql.Clob;
import java.sql.Connection;
import java.sql.DatabaseMetaData;
import java.sql.NClob;
import java.sql.PreparedStatement;
import java.sql.SQLClientInfoException;
import java.sql.SQLException;
import java.sql.SQLWarning;
import java.sql.SQLXML;
import java.sql.Savepoint;
import java.sql.Statement;
import java.sql.Struct;
import java.util.Map;
import java.util.Properties;
/**
 *
 * @author Luiz Augusto Prado
 * www.codigorapido.com.br
 */
public class ConnectionDB implements Connection
{
    private boolean isfree = false;
    private Connection conn;
    private int myTimeOpened;
    //==============================================================================
    // metodos de maior atenção
    //==============================================================================
    public ConnectionDB(Connection conn)
    {
        this.myTimeOpened = 0;
        this.conn = conn;
        this.isfree = false;
    }
    public void incrementMyTimeOpened(int myTimeOpened)
    {
        this.myTimeOpened += myTimeOpened;
    }
    public int getMyTimeOpened()
    {
        return myTimeOpened;
    } 
    public boolean isFree()
    {
        return isfree;
    }
    /**
     * Quando pegar a conexao setar isfree como falso para informar a thread
     * que a conexao está sendo utilizada por um usuario.
     * Ao mesmo tempo atualiza o tempo.
     * Se este tempo limite for ultrapassado, a conexao sera fechada
     * automaticamente pelo pool. Isso serve para o caso de
     * esquecermos de dar um close na conexao.
     */
    public void setFree(boolean isfree)
    {
        this.isfree = isfree;
        if(!this.isfree)
        {
            myTimeOpened=0;
        }
    }
    
    /**
     * Ao invés de fechar a conexão torna isfree igual a true
     */
    @Override
    public void close() throws SQLException
    {
        isfree=true;
    }
    /**
     * Fecha verdadeiramente a conexão que foi "decorada" nesta classe.
     * @throws SQLException
     */
    public void reallyClose() throws SQLException
    {
        isfree=false;
        this.conn.close();
        this.conn=null;
    }
    //=========================================================================
    // metodos de menor atenção
    //=========================================================================    
    @Override
    public <T> T unwrap(Class<T> iface) throws SQLException {
        return this.conn.unwrap(iface);
    }
    @Override
    public boolean isWrapperFor(Class<?> iface) throws SQLException {
        return this.conn.isWrapperFor(iface);
    }
    @Override
    public Statement createStatement() throws SQLException {
        return this.conn.createStatement();
    }
    @Override
    public PreparedStatement prepareStatement(String sql) throws SQLException {
        return this.conn.prepareStatement(sql);
    }
    @Override
    public CallableStatement prepareCall(String sql) throws SQLException {
        return this.conn.prepareCall(sql);
    }
    @Override
    public String nativeSQL(String sql) throws SQLException {
        return this.conn.nativeSQL(sql);
    }
    @Override
    public void setAutoCommit(boolean autoCommit) throws SQLException {
        this.conn.setAutoCommit(autoCommit);
    }
    @Override
    public boolean getAutoCommit() throws SQLException {
        return this.conn.getAutoCommit();
    }
    @Override
    public void commit() throws SQLException {
        this.conn.commit();
    }
    @Override
    public void rollback() throws SQLException {
        this.conn.rollback();
    }
    @Override
    public boolean isClosed() throws SQLException {
        return this.conn!=null?this.conn.isClosed():true ;
    }
    @Override
    public DatabaseMetaData getMetaData() throws SQLException {
        return this.conn.getMetaData();
    }
    @Override
    public void setReadOnly(boolean readOnly) throws SQLException {
        this.conn.setReadOnly(readOnly);
    }
    @Override
    public boolean isReadOnly() throws SQLException {
        return this.conn.isReadOnly();
    }
    @Override
    public void setCatalog(String catalog) throws SQLException {
        this.conn.setCatalog(catalog);
    }
    @Override
    public String getCatalog() throws SQLException {
        return this.conn.getCatalog();
    }
    @Override
    public void setTransactionIsolation(int level) throws SQLException {
        this.conn.setTransactionIsolation(level);
    }
    @Override
    public int getTransactionIsolation() throws SQLException {
        return this.conn.getTransactionIsolation();
    }
    @Override
    public SQLWarning getWarnings() throws SQLException {
        return this.conn.getWarnings();
    }
    @Override
    public void clearWarnings() throws SQLException {
        this.conn.clearWarnings();
    }
    @Override
    public Statement createStatement(int resultSetType, int resultSetConcurrency)
            throws SQLException {
        return this.conn.createStatement(resultSetType, resultSetConcurrency);
    }
    @Override
    public PreparedStatement prepareStatement(String sql, int resultSetType,
            int resultSetConcurrency) throws SQLException {
        return this.conn.prepareCall(sql, resultSetType, resultSetConcurrency);
    }
    @Override
    public CallableStatement prepareCall(String sql, int resultSetType,
            int resultSetConcurrency) throws SQLException {
        return this.conn.prepareCall(sql, resultSetType, resultSetConcurrency);
    }
    @Override
    public Map<String, Class><?>> getTypeMap() throws SQLException {
        return this.conn.getTypeMap();
    }
    @Override
    public void setTypeMap(Map<String, Class><?>> map) throws SQLException {
        this.conn.setTypeMap(map);
    }
    @Override
    public void setHoldability(int holdability) throws SQLException {
        this.conn.setHoldability(holdability);
    }
    @Override
    public int getHoldability() throws SQLException {
        return this.conn.getHoldability();
    }
    @Override
    public Savepoint setSavepoint() throws SQLException {
        return this.conn.setSavepoint();
    }
    @Override
    public Savepoint setSavepoint(String name) throws SQLException {
        return this.conn.setSavepoint(name);
    }
    @Override
    public void rollback(Savepoint savepoint) throws SQLException {
        this.conn.rollback();
    }
    @Override
    public void releaseSavepoint(Savepoint savepoint) throws SQLException {
        this.conn.releaseSavepoint(savepoint);
    }
    @Override
    public Statement createStatement(int resultSetType,
            int resultSetConcurrency, int resultSetHoldability)
            throws SQLException {
        return this.conn.createStatement(resultSetType, resultSetConcurrency, resultSetHoldability);
    }
    @Override
    public PreparedStatement prepareStatement(String sql, int resultSetType,
            int resultSetConcurrency, int resultSetHoldability)
            throws SQLException {
        return this.conn.prepareStatement(sql, resultSetType, resultSetConcurrency, 
resultSetHoldability);
    }
    @Override
    public CallableStatement prepareCall(String sql, int resultSetType,
            int resultSetConcurrency, int resultSetHoldability)
            throws SQLException {
        return this.conn.prepareCall(sql, resultSetType, resultSetConcurrency, 
resultSetHoldability);
    }
    @Override
    public PreparedStatement prepareStatement(String sql, int autoGeneratedKeys)
            throws SQLException {
        return this.conn.prepareStatement(sql, autoGeneratedKeys);
    }
    @Override
    public PreparedStatement prepareStatement(String sql, int[] columnIndexes)
            throws SQLException {
        return this.conn.prepareStatement(sql, columnIndexes);
    }
    @Override
    public PreparedStatement prepareStatement(String sql, String[] columnNames)
            throws SQLException {
        return this.conn.prepareStatement(sql, columnNames);
    }
    @Override
    public Clob createClob() throws SQLException {
        return this.conn.createClob();
    }
    @Override
    public Blob createBlob() throws SQLException {
        return this.conn.createBlob();
    }
    @Override
    public NClob createNClob() throws SQLException {
        return this.conn.createNClob();
    }
    @Override
    public SQLXML createSQLXML() throws SQLException {
        return this.conn.createSQLXML();
    }
    @Override
    public boolean isValid(int timeout) throws SQLException {
        return this.conn.isValid(timeout);
    }
    @Override
    public void setClientInfo(String name, String value)
            throws SQLClientInfoException {
        this.conn.setClientInfo(name, value);
    }
    @Override
    public void setClientInfo(Properties properties)
            throws SQLClientInfoException {
        this.conn.setClientInfo(properties);
    }
    @Override
    public String getClientInfo(String name) throws SQLException {
        return this.conn.getClientInfo(name);
    }
    @Override
    public Properties getClientInfo() throws SQLException {
        return this.conn.getClientInfo();
    }
    @Override
    public Array createArrayOf(String typeName, Object[] elements)
            throws SQLException {
        return this.conn.createArrayOf(typeName, elements);
    }
    @Override
    public Struct createStruct(String typeName, Object[] attributes)
            throws SQLException {
        return this.conn.createStruct(typeName, attributes);
    }
}
                     ConnectionPool para o Singleton do Pool de conexões
package PoolJDBC;
import java.sql.DriverManager;
import java.sql.SQLException;
import java.util.ArrayList;
import java.util.Collections;
import java.util.Iterator;
import java.util.List;
import java.util.logging.Level;
import java.util.logging.Logger;
/**
 *
 * @author Luiz Augusto Prado
 * www.codigorapido.com.br
 */
public class ConnectionPool implements Runnable
{
    private ConnectionPool pool = null;
    private Thread thread;
    private static ConnectionInterface connI;
    private final List<ConnectionDB> AllConnections = 
                               Collections.synchronizedList(new ArrayList<ConnectionDB>());
    public ConnectionPool(ConnectionInterface conn)
    {
        connI = conn;
    }
    /**
     *      carrega driver;
     *      cria o minimo de conexoes em estado livre;
     *      inicia thread de verificacao do tempo das conexoes.
     */
    private ConnectionPool()
    {
        try
        {
            Class.forName(connI.getDriver());
            System.out.println("driver : " + connI.getDriver());
        }
        catch (ClassNotFoundException ex)
        {
            System.out.println("Nao foi possivel encontrar driver para conexão com o banco de dados: 
" + ex.getMessage());
        }
        for (int i = 0; i < connI.getMinOfConnections(); i++)
        {
            try
            {
                ConnectionDB c = createConnection();
                c.setFree(true);
                AllConnections.add(c);
            }
            catch (Exception ex)
            {
                Logger.getLogger(ConnectionPool.class.getName()).log(Level.SEVERE, null, ex);
            }
        }
        thread = new Thread(this);
        thread.start();
    }
    public void run()
    {
        int i = 0;
        while (true)
        {
            try
            {
                synchronized (AllConnections)
                {
                    // =================================================
                    // excluirá o numero de conexões que ultrapassar o minimo.
                    //i = connI.getMinOfConnections();
                    // =================================================
                    i = 0;
                    while (i < AllConnections.size())
                    {
                        if(AllConnections.get(i).getMyTimeOpened() >= connI.getTimeToStandConnections() )
                        {
                            AllConnections.get(i).reallyClose();
                            AllConnections.remove(i);
                            i­­;
                        }
                        else
                        {
                            // 10 segundos
                            AllConnections.get(i).incrementMyTimeOpened(10000);
                        }
                        i++;
                    }
                }
                if ( AllConnections.size() == 0 )
                {
                    System.out.println("pool vazio");
                    break;
                }
                // 10 segundos
                Thread.sleep(10000);
            }
            catch (SQLException ex)
            {
                System.out.println("SQLException" + ex.getMessage());
            }
            catch (InterruptedException e)
            {
                System.out.println("InterruptedException" + e.getMessage());
            }
        }
    }
    private ConnectionDB createConnection() throws Exception
    {
        ConnectionDB con;
        try
        {
            con = new ConnectionDB(DriverManager.getConnection(connI.getUrl(), connI.getUser(), 
connI.getPass()));
            System.out.println("conexao criada");
        }
        catch (Exception ex)
        {
            throw new Exception("Nao foi possivel criar a conexao com banco de dados: " + 
ex.getMessage());
        }
        return con;
    }
    public ConnectionDB newConnection() throws Exception
    {
        if ( pool == null )
        {
            pool = new ConnectionPool();
            System.out.println("pool criado");
        }
        ConnectionDB con = null;
        synchronized (AllConnections)
        {
            Iterator<ConnectionDB> i = AllConnections.iterator();
            while (i.hasNext())
            {
                ConnectionDB rec = i.next();
                if ( rec.isFree() )
                {
                    con = rec;
                    break;
                }
            }
            if ( con == null && AllConnections.size() < connI.getMaxOfConnections() )
            {
                con = createConnection();
            }
        }
        if ( con != null )
        {
            System.out.println("conexao ocupada");
            con.setFree(false);
            return con;
        }
        Thread.sleep(50);
        return newConnection();
    }
    public void closeAllConnections() throws SQLException
    {
        synchronized (AllConnections)
        {
            System.out.println("Fechando conexoes");
            while (AllConnections.size()>0)
            {
                AllConnections.get(0).reallyClose();
                AllConnections.remove(0);
            }
        }
        pool = null;
    }
}
                                 Testando o Pool de conexões
package PoolJDBC;
import java.sql.SQLException;
import java.util.logging.Level;
import java.util.logging.Logger;
/**
 *
 * @author Luiz Augusto Prado
 * www.codigorapido.com.br
 */
public class Teste extends ConnectionPool
{
    private static Teste pool = new Teste();
    private Teste()
    {
        super(new ConnectionsProperties2() );
    }
    @SuppressWarnings("static­access")
    public static ConnectionDB getConnection() throws Exception
    {
        return pool.newConnection();
    }
    @SuppressWarnings("static­access")
    public static void closeConnections() throws SQLException
    {
        pool.closeAllConnections();
    }
    // implemento uma classe com as propriedades basicas da conexão
    public static class ConnectionsProperties2 implements ConnectionInterface
    {
        int minConnections=4;
        public String getDriver()
        {
            return "com.mysql.jdbc.Driver";
        }
        public String getUrl()
        {
            return "jdbc:mysql:///db_condominio";
        }
        public String getUser()
        {
            return "root";
        }
        public String getPass()
        {
            return "root";
        }
        public int getMinOfConnections()
        {
            return minConnections;
        }
        public int getMaxOfConnections()
        {
            return 8;
        }
        public int getTimeToStandConnections()
        {
            return 20000;
        }
    }
    public static void main(String[] args)
    {
        try
        { 
            ConnectionDB c1 = Teste.getConnection();
            //c1.close();
            //Teste.closeConnections();
            Thread.sleep(21000);
            ConnectionDB c2 = Teste.getConnection();
            Thread.sleep(2000);
            c2.close();
            Thread.sleep(2000);
            ConnectionDB c3 = Teste.getConnection();
            Thread.sleep(2000);
            c3.close();
        }
        catch (Exception ex)
        {
            Logger.getLogger(Teste.class.getName()).log(Level.SEVERE, null, ex);
        }
    }
}