public Connection getConnection() throws SQLException {

        PooledConnection pooledConnection = null;

        synchronized (this) {
            if (!initialized) {
                if (initialSize > maxPoolSize) {
                    throw new SQLException("Initial size of " + initialSize
                            + " exceeds max. pool size of " + maxPoolSize);
                }
                logInfo("Pre-initializing " + initialSize
                        + " physical connections");

                for (int i = 0; i < initialSize; i++) {
                    connectionsInactive.add(createNewConnection());
                }
                initialized = true;
            }

            long loginTimeoutExpiration = calculateLoginTimeoutExpiration();

            //each waiting thread will spin around in this loop until either
            //
            // a) a connection becomes available
            // b) the login timeout passes. Results in SQLException.
            // c) the thread is interrupted while waiting for an available connection
            // d) the connection pool is closed. Results in SQLException.
            //
            // the reason the threads spin in a loop is that they should always check all options
            // (available + space for new  + abandoned) before waiting. In addition the threads will
            // repeat the close check before spinning a second time. That way all threads waiting
            // for a connection when the connection is closed will get an SQLException.
            while (pooledConnection == null) {
                if (this.isPoolClosed) {
                    throw new SQLException(
                        "The pool is closed. You cannot get anymore connections from it.");
                }

                // 1) Check if any connections available in the pool.
                pooledConnection = dequeueFirstIfAny();

                if (pooledConnection != null) {
                    return wrapConnectionAndMarkAsInUse(pooledConnection);
                }

                // 2) Check if the pool has space for new connections and create one if it does.
                if (poolHasSpaceForNewConnections()) {
                    pooledConnection = createNewConnection();

                    return wrapConnectionAndMarkAsInUse(pooledConnection);
                }

                // 3) Check if connection pool has session timeout. If yes,
                // check if any connections has timed out. Return one if there are any.
                if (this.sessionTimeout > 0) {
                    reclaimAbandonedConnections();

                    //check if any connections were closed during the time out check.
                    pooledConnection = dequeueFirstIfAny();

                    if (pooledConnection != null) {
                        return wrapConnectionAndMarkAsInUse(pooledConnection);
                    }
                }

                // 4) wait until a connection becomes available or the login timeout passes (if set).
                doWait(loginTimeoutExpiration);
            }

            return wrapConnectionAndMarkAsInUse(pooledConnection);
        }
    }
public Connection getConnection ( ) throws SQLException { PooledConnection pooledConnection = null ; synchronized ( this ) { if ( ! initialized ) { if ( initialSize > maxPoolSize ) { throw new SQLException ( "Initial size of " + initialSize + " exceeds max. pool size of " + maxPoolSize ) ; } logInfo ( "Pre-initializing " + initialSize + " physical connections" ) ; for ( int i = 0 ; i < initialSize ; i ++ ) { connectionsInactive . add ( createNewConnection ( ) ) ; } initialized = true ; } long loginTimeoutExpiration = calculateLoginTimeoutExpiration ( ) ; while ( pooledConnection == null ) { if ( this . isPoolClosed ) { throw new SQLException ( "The pool is closed. You cannot get anymore connections from it." ) ; } pooledConnection = dequeueFirstIfAny ( ) ; if ( pooledConnection != null ) { return wrapConnectionAndMarkAsInUse ( pooledConnection ) ; } if ( poolHasSpaceForNewConnections ( ) ) { pooledConnection = createNewConnection ( ) ; return wrapConnectionAndMarkAsInUse ( pooledConnection ) ; } if ( this . sessionTimeout > 0 ) { reclaimAbandonedConnections ( ) ; pooledConnection = dequeueFirstIfAny ( ) ; if ( pooledConnection != null ) { return wrapConnectionAndMarkAsInUse ( pooledConnection ) ; } } doWait ( loginTimeoutExpiration ) ; } return wrapConnectionAndMarkAsInUse ( pooledConnection ) ; } }
This method will return a valid connection as fast as possible. Here is the sequence of events:

<ol>
<li>First it will try to take a ready connection from the pool.</li>
<li>If the pool doesn't have any ready connections this method will check
if the pool has space for new connections. If yes, a new connection is created and inserted
into the pool.</li>
<li>If the pool is already at maximum size this method will check for abandoned
connections among the connections given out earlier.
If any of the connections are abandoned it will be reclaimed, reset and
given out.</li>
<li>If there are no abandoned connections this method waits until a connection becomes
available in the pool, or until the login time out time has passed (if login timeout set).</li>
</ol>

This sequence means that the pool will not grow till max size as long as there are available connections
in the pool. Only when no connections are available will it spend time creating new connections.
In addition it will not spend
time reclaiming abandoned connections until it's absolutely necessary. Only when no new connections
can be created. Ultimately it only blocks if there really are no available connections,
none can be created and none can be reclaimed. Since the
pool is passive this is the sequence of events that should give the highest performance possible
for giving out connections from the pool.

<br/><br/>
Perhaps it is faster to reclaim a connection if possible than to create a new one. If so, it would be faster
to reclaim existing connections before creating new ones. It may also preserve resources better.
However, assuming that there will not often be abandoned connections, that programs most often
remember to close them, on the average the reclaim check is only going to be "wasted overhead".
It will only rarely result in a usable connection. In that perspective it should be faster
to only do the reclaim check when no connections can be created.

@throws SQLException