/*
 * Licensed to the Apache Software Foundation (ASF) under one or more
 * contributor license agreements.  See the NOTICE file distributed with
 * this work for additional information regarding copyright ownership.
 * The ASF licenses this file to You under the Apache License, Version 2.0
 * (the "License"); you may not use this file except in compliance with
 * the License.  You may obtain a copy of the License at
 *
 *      http://www.apache.org/licenses/LICENSE-2.0
 *
 * Unless required by applicable law or agreed to in writing, software
 * distributed under the License is distributed on an "AS IS" BASIS,
 * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
 * See the License for the specific language governing permissions and
 * limitations under the License.
 */
package org.apache.commons.pool2.impl;

import org.apache.commons.pool2.ObjectPool;
import org.apache.commons.pool2.PoolUtils;
import org.apache.commons.pool2.PooledObject;
import org.apache.commons.pool2.PooledObjectFactory;
import org.apache.commons.pool2.PooledObjectState;
import org.apache.commons.pool2.SwallowedExceptionListener;
import org.apache.commons.pool2.TrackedUse;
import org.apache.commons.pool2.UsageTracking;

import java.util.ArrayList;
import java.util.HashSet;
import java.util.Iterator;
import java.util.Map;
import java.util.NoSuchElementException;
import java.util.Set;
import java.util.concurrent.ConcurrentHashMap;
import java.util.concurrent.TimeUnit;
import java.util.concurrent.atomic.AtomicLong;

A configurable ObjectPool implementation.

When coupled with the appropriate PooledObjectFactory, GenericObjectPool provides robust pooling functionality for arbitrary objects.

Optionally, one may configure the pool to examine and possibly evict objects as they sit idle in the pool and to ensure that a minimum number of idle objects are available. This is performed by an "idle object eviction" thread, which runs asynchronously. Caution should be used when configuring this optional feature. Eviction runs contend with client threads for access to objects in the pool, so if they run too frequently performance issues may result.

The pool can also be configured to detect and remove "abandoned" objects, i.e. objects that have been checked out of the pool but neither used nor returned before the configured removeAbandonedTimeout. Abandoned object removal can be configured to happen when borrowObject is invoked and the pool is close to starvation, or it can be executed by the idle object evictor, or both. If pooled objects implement the TrackedUse interface, their last use will be queried using the getLastUsed method on that interface; otherwise abandonment is determined by how long an object has been checked out from the pool.

Implementation note: To prevent possible deadlocks, care has been taken to ensure that no call to a factory method will occur within a synchronization block. See POOL-125 and DBCP-44 for more information.

This class is intended to be thread-safe.

Type parameters:
  • <T> – Type of element pooled in this pool.
See Also:
Since:2.0
/** * A configurable {@link ObjectPool} implementation. * <p> * When coupled with the appropriate {@link PooledObjectFactory}, * <code>GenericObjectPool</code> provides robust pooling functionality for * arbitrary objects.</p> * <p> * Optionally, one may configure the pool to examine and possibly evict objects * as they sit idle in the pool and to ensure that a minimum number of idle * objects are available. This is performed by an "idle object eviction" thread, * which runs asynchronously. Caution should be used when configuring this * optional feature. Eviction runs contend with client threads for access to * objects in the pool, so if they run too frequently performance issues may * result.</p> * <p> * The pool can also be configured to detect and remove "abandoned" objects, * i.e. objects that have been checked out of the pool but neither used nor * returned before the configured * {@link AbandonedConfig#getRemoveAbandonedTimeout() removeAbandonedTimeout}. * Abandoned object removal can be configured to happen when * <code>borrowObject</code> is invoked and the pool is close to starvation, or * it can be executed by the idle object evictor, or both. If pooled objects * implement the {@link TrackedUse} interface, their last use will be queried * using the <code>getLastUsed</code> method on that interface; otherwise * abandonment is determined by how long an object has been checked out from * the pool.</p> * <p> * Implementation note: To prevent possible deadlocks, care has been taken to * ensure that no call to a factory method will occur within a synchronization * block. See POOL-125 and DBCP-44 for more information.</p> * <p> * This class is intended to be thread-safe.</p> * * @see GenericKeyedObjectPool * * @param <T> Type of element pooled in this pool. * * @since 2.0 */
public class GenericObjectPool<T> extends BaseGenericObjectPool<T> implements ObjectPool<T>, GenericObjectPoolMXBean, UsageTracking<T> {
Creates a new GenericObjectPool using defaults from GenericObjectPoolConfig.
Params:
  • factory – The object factory to be used to create object instances used by this pool
/** * Creates a new <code>GenericObjectPool</code> using defaults from * {@link GenericObjectPoolConfig}. * * @param factory The object factory to be used to create object instances * used by this pool */
public GenericObjectPool(final PooledObjectFactory<T> factory) { this(factory, new GenericObjectPoolConfig<T>()); }
Creates a new GenericObjectPool using a specific configuration.
Params:
  • factory – The object factory to be used to create object instances used by this pool
  • config – The configuration to use for this pool instance. The configuration is used by value. Subsequent changes to the configuration object will not be reflected in the pool.
/** * Creates a new <code>GenericObjectPool</code> using a specific * configuration. * * @param factory The object factory to be used to create object instances * used by this pool * @param config The configuration to use for this pool instance. The * configuration is used by value. Subsequent changes to * the configuration object will not be reflected in the * pool. */
public GenericObjectPool(final PooledObjectFactory<T> factory, final GenericObjectPoolConfig<T> config) { super(config, ONAME_BASE, config.getJmxNamePrefix()); if (factory == null) { jmxUnregister(); // tidy up throw new IllegalArgumentException("factory may not be null"); } this.factory = factory; idleObjects = new LinkedBlockingDeque<>(config.getFairness()); setConfig(config); }
Creates a new GenericObjectPool that tracks and destroys objects that are checked out, but never returned to the pool.
Params:
  • factory – The object factory to be used to create object instances used by this pool
  • config – The base pool configuration to use for this pool instance. The configuration is used by value. Subsequent changes to the configuration object will not be reflected in the pool.
  • abandonedConfig – Configuration for abandoned object identification and removal. The configuration is used by value.
/** * Creates a new <code>GenericObjectPool</code> that tracks and destroys * objects that are checked out, but never returned to the pool. * * @param factory The object factory to be used to create object instances * used by this pool * @param config The base pool configuration to use for this pool instance. * The configuration is used by value. Subsequent changes to * the configuration object will not be reflected in the * pool. * @param abandonedConfig Configuration for abandoned object identification * and removal. The configuration is used by value. */
public GenericObjectPool(final PooledObjectFactory<T> factory, final GenericObjectPoolConfig<T> config, final AbandonedConfig abandonedConfig) { this(factory, config); setAbandonedConfig(abandonedConfig); }
Returns the cap on the number of "idle" instances in the pool. If maxIdle is set too low on heavily loaded systems it is possible you will see objects being destroyed and almost immediately new objects being created. This is a result of the active threads momentarily returning objects faster than they are requesting them, causing the number of idle objects to rise above maxIdle. The best value for maxIdle for heavily loaded system will vary but the default is a good starting point.
See Also:
Returns:the maximum number of "idle" instances that can be held in the pool or a negative value if there is no limit
/** * Returns the cap on the number of "idle" instances in the pool. If maxIdle * is set too low on heavily loaded systems it is possible you will see * objects being destroyed and almost immediately new objects being created. * This is a result of the active threads momentarily returning objects * faster than they are requesting them, causing the number of idle * objects to rise above maxIdle. The best value for maxIdle for heavily * loaded system will vary but the default is a good starting point. * * @return the maximum number of "idle" instances that can be held in the * pool or a negative value if there is no limit * * @see #setMaxIdle */
@Override public int getMaxIdle() { return maxIdle; }
Returns the cap on the number of "idle" instances in the pool. If maxIdle is set too low on heavily loaded systems it is possible you will see objects being destroyed and almost immediately new objects being created. This is a result of the active threads momentarily returning objects faster than they are requesting them, causing the number of idle objects to rise above maxIdle. The best value for maxIdle for heavily loaded system will vary but the default is a good starting point.
Params:
  • maxIdle – The cap on the number of "idle" instances in the pool. Use a negative value to indicate an unlimited number of idle instances
See Also:
/** * Returns the cap on the number of "idle" instances in the pool. If maxIdle * is set too low on heavily loaded systems it is possible you will see * objects being destroyed and almost immediately new objects being created. * This is a result of the active threads momentarily returning objects * faster than they are requesting them, causing the number of idle * objects to rise above maxIdle. The best value for maxIdle for heavily * loaded system will vary but the default is a good starting point. * * @param maxIdle * The cap on the number of "idle" instances in the pool. Use a * negative value to indicate an unlimited number of idle * instances * * @see #getMaxIdle */
public void setMaxIdle(final int maxIdle) { this.maxIdle = maxIdle; }
Sets the target for the minimum number of idle objects to maintain in the pool. This setting only has an effect if it is positive and BaseGenericObjectPool.getTimeBetweenEvictionRunsMillis() is greater than zero. If this is the case, an attempt is made to ensure that the pool has the required minimum number of instances during idle object eviction runs.

If the configured value of minIdle is greater than the configured value for maxIdle then the value of maxIdle will be used instead.

Params:
  • minIdle – The minimum number of objects.
See Also:
/** * Sets the target for the minimum number of idle objects to maintain in * the pool. This setting only has an effect if it is positive and * {@link #getTimeBetweenEvictionRunsMillis()} is greater than zero. If this * is the case, an attempt is made to ensure that the pool has the required * minimum number of instances during idle object eviction runs. * <p> * If the configured value of minIdle is greater than the configured value * for maxIdle then the value of maxIdle will be used instead. * </p> * * @param minIdle * The minimum number of objects. * * @see #getMinIdle() * @see #getMaxIdle() * @see #getTimeBetweenEvictionRunsMillis() */
public void setMinIdle(final int minIdle) { this.minIdle = minIdle; }
Returns the target for the minimum number of idle objects to maintain in the pool. This setting only has an effect if it is positive and BaseGenericObjectPool.getTimeBetweenEvictionRunsMillis() is greater than zero. If this is the case, an attempt is made to ensure that the pool has the required minimum number of instances during idle object eviction runs.

If the configured value of minIdle is greater than the configured value for maxIdle then the value of maxIdle will be used instead.

See Also:
Returns:The minimum number of objects.
/** * Returns the target for the minimum number of idle objects to maintain in * the pool. This setting only has an effect if it is positive and * {@link #getTimeBetweenEvictionRunsMillis()} is greater than zero. If this * is the case, an attempt is made to ensure that the pool has the required * minimum number of instances during idle object eviction runs. * <p> * If the configured value of minIdle is greater than the configured value * for maxIdle then the value of maxIdle will be used instead. * </p> * * @return The minimum number of objects. * * @see #setMinIdle(int) * @see #setMaxIdle(int) * @see #setTimeBetweenEvictionRunsMillis(long) */
@Override public int getMinIdle() { final int maxIdleSave = getMaxIdle(); if (this.minIdle > maxIdleSave) { return maxIdleSave; } return minIdle; }
Gets whether or not abandoned object removal is configured for this pool.
Returns:true if this pool is configured to detect and remove abandoned objects
/** * Gets whether or not abandoned object removal is configured for this pool. * * @return true if this pool is configured to detect and remove * abandoned objects */
@Override public boolean isAbandonedConfig() { return abandonedConfig != null; }
Gets whether this pool identifies and logs any abandoned objects.
See Also:
Returns:true if abandoned object removal is configured for this pool and removal events are to be logged otherwise false
/** * Gets whether this pool identifies and logs any abandoned objects. * * @return {@code true} if abandoned object removal is configured for this * pool and removal events are to be logged otherwise {@code false} * * @see AbandonedConfig#getLogAbandoned() */
@Override public boolean getLogAbandoned() { final AbandonedConfig ac = this.abandonedConfig; return ac != null && ac.getLogAbandoned(); }
Gets whether a check is made for abandoned objects when an object is borrowed from this pool.
See Also:
Returns:true if abandoned object removal is configured to be activated by borrowObject otherwise false
/** * Gets whether a check is made for abandoned objects when an object is borrowed * from this pool. * * @return {@code true} if abandoned object removal is configured to be * activated by borrowObject otherwise {@code false} * * @see AbandonedConfig#getRemoveAbandonedOnBorrow() */
@Override public boolean getRemoveAbandonedOnBorrow() { final AbandonedConfig ac = this.abandonedConfig; return ac != null && ac.getRemoveAbandonedOnBorrow(); }
Gets whether a check is made for abandoned objects when the evictor runs.
See Also:
Returns:true if abandoned object removal is configured to be activated when the evictor runs otherwise false
/** * Gets whether a check is made for abandoned objects when the evictor runs. * * @return {@code true} if abandoned object removal is configured to be * activated when the evictor runs otherwise {@code false} * * @see AbandonedConfig#getRemoveAbandonedOnMaintenance() */
@Override public boolean getRemoveAbandonedOnMaintenance() { final AbandonedConfig ac = this.abandonedConfig; return ac != null && ac.getRemoveAbandonedOnMaintenance(); }
Obtains the timeout before which an object will be considered to be abandoned by this pool.
See Also:
Returns:The abandoned object timeout in seconds if abandoned object removal is configured for this pool; Integer.MAX_VALUE otherwise.
/** * Obtains the timeout before which an object will be considered to be * abandoned by this pool. * * @return The abandoned object timeout in seconds if abandoned object * removal is configured for this pool; Integer.MAX_VALUE otherwise. * * @see AbandonedConfig#getRemoveAbandonedTimeout() */
@Override public int getRemoveAbandonedTimeout() { final AbandonedConfig ac = this.abandonedConfig; return ac != null ? ac.getRemoveAbandonedTimeout() : Integer.MAX_VALUE; }
Sets the base pool configuration.
Params:
  • conf – the new configuration to use. This is used by value.
See Also:
/** * Sets the base pool configuration. * * @param conf the new configuration to use. This is used by value. * * @see GenericObjectPoolConfig */
public void setConfig(final GenericObjectPoolConfig<T> conf) { super.setConfig(conf); setMaxIdle(conf.getMaxIdle()); setMinIdle(conf.getMinIdle()); setMaxTotal(conf.getMaxTotal()); }
Sets the abandoned object removal configuration.
Params:
  • abandonedConfig – the new configuration to use. This is used by value.
See Also:
/** * Sets the abandoned object removal configuration. * * @param abandonedConfig the new configuration to use. This is used by value. * * @see AbandonedConfig */
public void setAbandonedConfig(final AbandonedConfig abandonedConfig) { if (abandonedConfig == null) { this.abandonedConfig = null; } else { this.abandonedConfig = new AbandonedConfig(); this.abandonedConfig.setLogAbandoned(abandonedConfig.getLogAbandoned()); this.abandonedConfig.setLogWriter(abandonedConfig.getLogWriter()); this.abandonedConfig.setRemoveAbandonedOnBorrow(abandonedConfig.getRemoveAbandonedOnBorrow()); this.abandonedConfig.setRemoveAbandonedOnMaintenance(abandonedConfig.getRemoveAbandonedOnMaintenance()); this.abandonedConfig.setRemoveAbandonedTimeout(abandonedConfig.getRemoveAbandonedTimeout()); this.abandonedConfig.setUseUsageTracking(abandonedConfig.getUseUsageTracking()); this.abandonedConfig.setRequireFullStackTrace(abandonedConfig.getRequireFullStackTrace()); } }
Obtains a reference to the factory used to create, destroy and validate the objects used by this pool.
Returns:the factory
/** * Obtains a reference to the factory used to create, destroy and validate * the objects used by this pool. * * @return the factory */
public PooledObjectFactory<T> getFactory() { return factory; } /** * Equivalent to <code>{@link #borrowObject(long) * borrowObject}({@link #getMaxWaitMillis()})</code>. * <p> * {@inheritDoc} * </p> */ @Override public T borrowObject() throws Exception { return borrowObject(getMaxWaitMillis()); }
Borrows an object from the pool using the specific waiting time which only applies if BaseGenericObjectPool.getBlockWhenExhausted() is true.

If there is one or more idle instance available in the pool, then an idle instance will be selected based on the value of BaseGenericObjectPool.getLifo(), activated and returned. If activation fails, or testOnBorrow is set to true and validation fails, the instance is destroyed and the next available instance is examined. This continues until either a valid instance is returned or there are no more idle instances available.

If there are no idle instances available in the pool, behavior depends on the maxTotal, (if applicable) BaseGenericObjectPool.getBlockWhenExhausted() and the value passed in to the borrowMaxWaitMillis parameter. If the number of instances checked out from the pool is less than maxTotal, a new instance is created, activated and (if applicable) validated and returned to the caller. If validation fails, a NoSuchElementException is thrown.

If the pool is exhausted (no available idle instances and no capacity to create new ones), this method will either block (if BaseGenericObjectPool.getBlockWhenExhausted() is true) or throw a NoSuchElementException (if BaseGenericObjectPool.getBlockWhenExhausted() is false). The length of time that this method will block when BaseGenericObjectPool.getBlockWhenExhausted() is true is determined by the value passed in to the borrowMaxWaitMillis parameter.

When the pool is exhausted, multiple calling threads may be simultaneously blocked waiting for instances to become available. A "fairness" algorithm has been implemented to ensure that threads receive available instances in request arrival order.

Params:
  • borrowMaxWaitMillis – The time to wait in milliseconds for an object to become available
Throws:
Returns:object instance from the pool
/** * Borrows an object from the pool using the specific waiting time which only * applies if {@link #getBlockWhenExhausted()} is true. * <p> * If there is one or more idle instance available in the pool, then an * idle instance will be selected based on the value of {@link #getLifo()}, * activated and returned. If activation fails, or {@link #getTestOnBorrow() * testOnBorrow} is set to <code>true</code> and validation fails, the * instance is destroyed and the next available instance is examined. This * continues until either a valid instance is returned or there are no more * idle instances available. * </p> * <p> * If there are no idle instances available in the pool, behavior depends on * the {@link #getMaxTotal() maxTotal}, (if applicable) * {@link #getBlockWhenExhausted()} and the value passed in to the * <code>borrowMaxWaitMillis</code> parameter. If the number of instances * checked out from the pool is less than <code>maxTotal,</code> a new * instance is created, activated and (if applicable) validated and returned * to the caller. If validation fails, a <code>NoSuchElementException</code> * is thrown. * </p> * <p> * If the pool is exhausted (no available idle instances and no capacity to * create new ones), this method will either block (if * {@link #getBlockWhenExhausted()} is true) or throw a * <code>NoSuchElementException</code> (if * {@link #getBlockWhenExhausted()} is false). The length of time that this * method will block when {@link #getBlockWhenExhausted()} is true is * determined by the value passed in to the <code>borrowMaxWaitMillis</code> * parameter. * </p> * <p> * When the pool is exhausted, multiple calling threads may be * simultaneously blocked waiting for instances to become available. A * "fairness" algorithm has been implemented to ensure that threads receive * available instances in request arrival order. * </p> * * @param borrowMaxWaitMillis The time to wait in milliseconds for an object * to become available * * @return object instance from the pool * * @throws NoSuchElementException if an instance cannot be returned * * @throws Exception if an object instance cannot be returned due to an * error */
public T borrowObject(final long borrowMaxWaitMillis) throws Exception { assertOpen(); final AbandonedConfig ac = this.abandonedConfig; if (ac != null && ac.getRemoveAbandonedOnBorrow() && (getNumIdle() < 2) && (getNumActive() > getMaxTotal() - 3) ) { removeAbandoned(ac); } PooledObject<T> p = null; // Get local copy of current config so it is consistent for entire // method execution final boolean blockWhenExhausted = getBlockWhenExhausted(); boolean create; final long waitTime = System.currentTimeMillis(); while (p == null) { create = false; p = idleObjects.pollFirst(); if (p == null) { p = create(); if (p != null) { create = true; } } if (blockWhenExhausted) { if (p == null) { if (borrowMaxWaitMillis < 0) { p = idleObjects.takeFirst(); } else { p = idleObjects.pollFirst(borrowMaxWaitMillis, TimeUnit.MILLISECONDS); } } if (p == null) { throw new NoSuchElementException( "Timeout waiting for idle object"); } } else { if (p == null) { throw new NoSuchElementException("Pool exhausted"); } } if (!p.allocate()) { p = null; } if (p != null) { try { factory.activateObject(p); } catch (final Exception e) { try { destroy(p); } catch (final Exception e1) { // Ignore - activation failure is more important } p = null; if (create) { final NoSuchElementException nsee = new NoSuchElementException( "Unable to activate object"); nsee.initCause(e); throw nsee; } } if (p != null && getTestOnBorrow()) { boolean validate = false; Throwable validationThrowable = null; try { validate = factory.validateObject(p); } catch (final Throwable t) { PoolUtils.checkRethrow(t); validationThrowable = t; } if (!validate) { try { destroy(p); destroyedByBorrowValidationCount.incrementAndGet(); } catch (final Exception e) { // Ignore - validation failure is more important } p = null; if (create) { final NoSuchElementException nsee = new NoSuchElementException( "Unable to validate object"); nsee.initCause(validationThrowable); throw nsee; } } } } } updateStatsBorrow(p, System.currentTimeMillis() - waitTime); return p.getObject(); }
{@inheritDoc}

If maxIdle is set to a positive value and the number of idle instances has reached this value, the returning instance is destroyed.

If testOnReturn == true, the returning instance is validated before being returned to the idle instance pool. In this case, if validation fails, the instance is destroyed.

Exceptions encountered destroying objects for any reason are swallowed but notified via a SwallowedExceptionListener.

/** * {@inheritDoc} * <p> * If {@link #getMaxIdle() maxIdle} is set to a positive value and the * number of idle instances has reached this value, the returning instance * is destroyed. * </p> * <p> * If {@link #getTestOnReturn() testOnReturn} == true, the returning * instance is validated before being returned to the idle instance pool. In * this case, if validation fails, the instance is destroyed. * </p> * <p> * Exceptions encountered destroying objects for any reason are swallowed * but notified via a {@link SwallowedExceptionListener}. * </p> */
@Override public void returnObject(final T obj) { final PooledObject<T> p = allObjects.get(new IdentityWrapper<>(obj)); if (p == null) { if (!isAbandonedConfig()) { throw new IllegalStateException( "Returned object not currently part of this pool"); } return; // Object was abandoned and removed } markReturningState(p); final long activeTime = p.getActiveTimeMillis(); if (getTestOnReturn() && !factory.validateObject(p)) { try { destroy(p); } catch (final Exception e) { swallowException(e); } try { ensureIdle(1, false); } catch (final Exception e) { swallowException(e); } updateStatsReturn(activeTime); return; } try { factory.passivateObject(p); } catch (final Exception e1) { swallowException(e1); try { destroy(p); } catch (final Exception e) { swallowException(e); } try { ensureIdle(1, false); } catch (final Exception e) { swallowException(e); } updateStatsReturn(activeTime); return; } if (!p.deallocate()) { throw new IllegalStateException( "Object has already been returned to this pool or is invalid"); } final int maxIdleSave = getMaxIdle(); if (isClosed() || maxIdleSave > -1 && maxIdleSave <= idleObjects.size()) { try { destroy(p); } catch (final Exception e) { swallowException(e); } } else { if (getLifo()) { idleObjects.addFirst(p); } else { idleObjects.addLast(p); } if (isClosed()) { // Pool closed while object was being added to idle objects. // Make sure the returned object is destroyed rather than left // in the idle object pool (which would effectively be a leak) clear(); } } updateStatsReturn(activeTime); }
{@inheritDoc}

Activation of this method decrements the active count and attempts to destroy the instance.

Throws:
/** * {@inheritDoc} * <p> * Activation of this method decrements the active count and attempts to * destroy the instance. * </p> * * @throws Exception if an exception occurs destroying the * object * @throws IllegalStateException if obj does not belong to this pool */
@Override public void invalidateObject(final T obj) throws Exception { final PooledObject<T> p = allObjects.get(new IdentityWrapper<>(obj)); if (p == null) { if (isAbandonedConfig()) { return; } throw new IllegalStateException( "Invalidated object not currently part of this pool"); } synchronized (p) { if (p.getState() != PooledObjectState.INVALID) { destroy(p); } } ensureIdle(1, false); }
Clears any objects sitting idle in the pool by removing them from the idle instance pool and then invoking the configured PooledObjectFactory.destroyObject(PooledObject) method on each idle instance.

Implementation notes:

  • This method does not destroy or effect in any way instances that are checked out of the pool when it is invoked.
  • Invoking this method does not prevent objects being returned to the idle instance pool, even during its execution. Additional instances may be returned while removed items are being destroyed.
  • Exceptions encountered destroying idle instances are swallowed but notified via a SwallowedExceptionListener.
/** * Clears any objects sitting idle in the pool by removing them from the * idle instance pool and then invoking the configured * {@link PooledObjectFactory#destroyObject(PooledObject)} method on each * idle instance. * <p> * Implementation notes: * </p> * <ul> * <li>This method does not destroy or effect in any way instances that are * checked out of the pool when it is invoked.</li> * <li>Invoking this method does not prevent objects being returned to the * idle instance pool, even during its execution. Additional instances may * be returned while removed items are being destroyed.</li> * <li>Exceptions encountered destroying idle instances are swallowed * but notified via a {@link SwallowedExceptionListener}.</li> * </ul> */
@Override public void clear() { PooledObject<T> p = idleObjects.poll(); while (p != null) { try { destroy(p); } catch (final Exception e) { swallowException(e); } p = idleObjects.poll(); } } @Override public int getNumActive() { return allObjects.size() - idleObjects.size(); } @Override public int getNumIdle() { return idleObjects.size(); }
Closes the pool. Once the pool is closed, borrowObject() will fail with IllegalStateException, but returnObject(Object) and invalidateObject(Object) will continue to work, with returned objects destroyed on return.

Destroys idle instances in the pool by invoking clear().

/** * Closes the pool. Once the pool is closed, {@link #borrowObject()} will * fail with IllegalStateException, but {@link #returnObject(Object)} and * {@link #invalidateObject(Object)} will continue to work, with returned * objects destroyed on return. * <p> * Destroys idle instances in the pool by invoking {@link #clear()}. * </p> */
@Override public void close() { if (isClosed()) { return; } synchronized (closeLock) { if (isClosed()) { return; } // Stop the evictor before the pool is closed since evict() calls // assertOpen() stopEvictor(); closed = true; // This clear removes any idle objects clear(); jmxUnregister(); // Release any threads that were waiting for an object idleObjects.interuptTakeWaiters(); } }
{@inheritDoc}

Successive activations of this method examine objects in sequence, cycling through objects in oldest-to-youngest order.

/** * {@inheritDoc} * <p> * Successive activations of this method examine objects in sequence, * cycling through objects in oldest-to-youngest order. * </p> */
@Override public void evict() throws Exception { assertOpen(); if (idleObjects.size() > 0) { PooledObject<T> underTest = null; final EvictionPolicy<T> evictionPolicy = getEvictionPolicy(); synchronized (evictionLock) { final EvictionConfig evictionConfig = new EvictionConfig( getMinEvictableIdleTimeMillis(), getSoftMinEvictableIdleTimeMillis(), getMinIdle()); final boolean testWhileIdle = getTestWhileIdle(); for (int i = 0, m = getNumTests(); i < m; i++) { if (evictionIterator == null || !evictionIterator.hasNext()) { evictionIterator = new EvictionIterator(idleObjects); } if (!evictionIterator.hasNext()) { // Pool exhausted, nothing to do here return; } try { underTest = evictionIterator.next(); } catch (final NoSuchElementException nsee) { // Object was borrowed in another thread // Don't count this as an eviction test so reduce i; i--; evictionIterator = null; continue; } if (!underTest.startEvictionTest()) { // Object was borrowed in another thread // Don't count this as an eviction test so reduce i; i--; continue; } // User provided eviction policy could throw all sorts of // crazy exceptions. Protect against such an exception // killing the eviction thread. boolean evict; try { evict = evictionPolicy.evict(evictionConfig, underTest, idleObjects.size()); } catch (final Throwable t) { // Slightly convoluted as SwallowedExceptionListener // uses Exception rather than Throwable PoolUtils.checkRethrow(t); swallowException(new Exception(t)); // Don't evict on error conditions evict = false; } if (evict) { destroy(underTest); destroyedByEvictorCount.incrementAndGet(); } else { if (testWhileIdle) { boolean active = false; try { factory.activateObject(underTest); active = true; } catch (final Exception e) { destroy(underTest); destroyedByEvictorCount.incrementAndGet(); } if (active) { if (!factory.validateObject(underTest)) { destroy(underTest); destroyedByEvictorCount.incrementAndGet(); } else { try { factory.passivateObject(underTest); } catch (final Exception e) { destroy(underTest); destroyedByEvictorCount.incrementAndGet(); } } } } if (!underTest.endEvictionTest(idleObjects)) { // TODO - May need to add code here once additional // states are used } } } } } final AbandonedConfig ac = this.abandonedConfig; if (ac != null && ac.getRemoveAbandonedOnMaintenance()) { removeAbandoned(ac); } }
Tries to ensure that getMinIdle() idle instances are available in the pool.
Throws:
  • Exception – If the associated factory throws an exception
Since:2.4
/** * Tries to ensure that {@link #getMinIdle()} idle instances are available * in the pool. * * @throws Exception If the associated factory throws an exception * @since 2.4 */
public void preparePool() throws Exception { if (getMinIdle() < 1) { return; } ensureMinIdle(); }
Attempts to create a new wrapped pooled object.

If there are BaseGenericObjectPool.getMaxTotal() objects already in circulation or in process of being created, this method returns null.

Throws:
  • Exception – if the object factory's makeObject fails
Returns:The new wrapped pooled object
/** * Attempts to create a new wrapped pooled object. * <p> * If there are {@link #getMaxTotal()} objects already in circulation * or in process of being created, this method returns null. * </p> * * @return The new wrapped pooled object * * @throws Exception if the object factory's {@code makeObject} fails */
private PooledObject<T> create() throws Exception { int localMaxTotal = getMaxTotal(); // This simplifies the code later in this method if (localMaxTotal < 0) { localMaxTotal = Integer.MAX_VALUE; } final long localStartTimeMillis = System.currentTimeMillis(); final long localMaxWaitTimeMillis = Math.max(getMaxWaitMillis(), 0); // Flag that indicates if create should: // - TRUE: call the factory to create an object // - FALSE: return null // - null: loop and re-test the condition that determines whether to // call the factory Boolean create = null; while (create == null) { synchronized (makeObjectCountLock) { final long newCreateCount = createCount.incrementAndGet(); if (newCreateCount > localMaxTotal) { // The pool is currently at capacity or in the process of // making enough new objects to take it to capacity. createCount.decrementAndGet(); if (makeObjectCount == 0) { // There are no makeObject() calls in progress so the // pool is at capacity. Do not attempt to create a new // object. Return and wait for an object to be returned create = Boolean.FALSE; } else { // There are makeObject() calls in progress that might // bring the pool to capacity. Those calls might also // fail so wait until they complete and then re-test if // the pool is at capacity or not. makeObjectCountLock.wait(localMaxWaitTimeMillis); } } else { // The pool is not at capacity. Create a new object. makeObjectCount++; create = Boolean.TRUE; } } // Do not block more if maxWaitTimeMillis is set. if (create == null && (localMaxWaitTimeMillis > 0 && System.currentTimeMillis() - localStartTimeMillis >= localMaxWaitTimeMillis)) { create = Boolean.FALSE; } } if (!create.booleanValue()) { return null; } final PooledObject<T> p; try { p = factory.makeObject(); if (getTestOnCreate() && !factory.validateObject(p)) { createCount.decrementAndGet(); return null; } } catch (final Throwable e) { createCount.decrementAndGet(); throw e; } finally { synchronized (makeObjectCountLock) { makeObjectCount--; makeObjectCountLock.notifyAll(); } } final AbandonedConfig ac = this.abandonedConfig; if (ac != null && ac.getLogAbandoned()) { p.setLogAbandoned(true); p.setRequireFullStackTrace(ac.getRequireFullStackTrace()); } createdCount.incrementAndGet(); allObjects.put(new IdentityWrapper<>(p.getObject()), p); return p; }
Destroys a wrapped pooled object.
Params:
  • toDestroy – The wrapped pooled object to destroy
Throws:
  • Exception – If the factory fails to destroy the pooled object cleanly
/** * Destroys a wrapped pooled object. * * @param toDestroy The wrapped pooled object to destroy * * @throws Exception If the factory fails to destroy the pooled object * cleanly */
private void destroy(final PooledObject<T> toDestroy) throws Exception { toDestroy.invalidate(); idleObjects.remove(toDestroy); allObjects.remove(new IdentityWrapper<>(toDestroy.getObject())); try { factory.destroyObject(toDestroy); } finally { destroyedCount.incrementAndGet(); createCount.decrementAndGet(); } if (idleObjects.isEmpty() && idleObjects.hasTakeWaiters()) { // POOL-356. // In case there are already threads waiting on something in the pool // (e.g. idleObjects.takeFirst(); then we need to provide them a fresh instance. // Otherwise they will be stuck forever (or until timeout) final PooledObject<T> freshPooled = create(); idleObjects.put(freshPooled); } } @Override void ensureMinIdle() throws Exception { ensureIdle(getMinIdle(), true); }
Tries to ensure that idleCount idle instances exist in the pool.

Creates and adds idle instances until either getNumIdle() reaches idleCount or the total number of objects (idle, checked out, or being created) reaches BaseGenericObjectPool.getMaxTotal(). If always is false, no instances are created unless there are threads waiting to check out instances from the pool.

Params:
  • idleCount – the number of idle instances desired
  • always – true means create instances even if the pool has no threads waiting
Throws:
  • Exception – if the factory's makeObject throws
/** * Tries to ensure that {@code idleCount} idle instances exist in the pool. * <p> * Creates and adds idle instances until either {@link #getNumIdle()} reaches {@code idleCount} * or the total number of objects (idle, checked out, or being created) reaches * {@link #getMaxTotal()}. If {@code always} is false, no instances are created unless * there are threads waiting to check out instances from the pool. * </p> * * @param idleCount the number of idle instances desired * @param always true means create instances even if the pool has no threads waiting * @throws Exception if the factory's makeObject throws */
private void ensureIdle(final int idleCount, final boolean always) throws Exception { if (idleCount < 1 || isClosed() || (!always && !idleObjects.hasTakeWaiters())) { return; } while (idleObjects.size() < idleCount) { final PooledObject<T> p = create(); if (p == null) { // Can't create objects, no reason to think another call to // create will work. Give up. break; } if (getLifo()) { idleObjects.addFirst(p); } else { idleObjects.addLast(p); } } if (isClosed()) { // Pool closed while object was being added to idle objects. // Make sure the returned object is destroyed rather than left // in the idle object pool (which would effectively be a leak) clear(); } }
Creates an object, and place it into the pool. addObject() is useful for "pre-loading" a pool with idle objects.

If there is no capacity available to add to the pool, this is a no-op (no exception, no impact to the pool).

/** * Creates an object, and place it into the pool. addObject() is useful for * "pre-loading" a pool with idle objects. * <p> * If there is no capacity available to add to the pool, this is a no-op * (no exception, no impact to the pool). </p> */
@Override public void addObject() throws Exception { assertOpen(); if (factory == null) { throw new IllegalStateException( "Cannot add objects without a factory."); } final PooledObject<T> p = create(); addIdleObject(p); }
Adds the provided wrapped pooled object to the set of idle objects for this pool. The object must already be part of the pool. If p is null, this is a no-op (no exception, but no impact on the pool).
Params:
  • p – The object to make idle
Throws:
  • Exception – If the factory fails to passivate the object
/** * Adds the provided wrapped pooled object to the set of idle objects for * this pool. The object must already be part of the pool. If {@code p} * is null, this is a no-op (no exception, but no impact on the pool). * * @param p The object to make idle * * @throws Exception If the factory fails to passivate the object */
private void addIdleObject(final PooledObject<T> p) throws Exception { if (p != null) { factory.passivateObject(p); if (getLifo()) { idleObjects.addFirst(p); } else { idleObjects.addLast(p); } } }
Calculates the number of objects to test in a run of the idle object evictor.
Returns:The number of objects to test for validity
/** * Calculates the number of objects to test in a run of the idle object * evictor. * * @return The number of objects to test for validity */
private int getNumTests() { final int numTestsPerEvictionRun = getNumTestsPerEvictionRun(); if (numTestsPerEvictionRun >= 0) { return Math.min(numTestsPerEvictionRun, idleObjects.size()); } return (int) (Math.ceil(idleObjects.size() / Math.abs((double) numTestsPerEvictionRun))); }
Recovers abandoned objects which have been checked out but not used since longer than the removeAbandonedTimeout.
Params:
  • ac – The configuration to use to identify abandoned objects
/** * Recovers abandoned objects which have been checked out but * not used since longer than the removeAbandonedTimeout. * * @param ac The configuration to use to identify abandoned objects */
private void removeAbandoned(final AbandonedConfig ac) { // Generate a list of abandoned objects to remove final long now = System.currentTimeMillis(); final long timeout = now - (ac.getRemoveAbandonedTimeout() * 1000L); final ArrayList<PooledObject<T>> remove = new ArrayList<>(); final Iterator<PooledObject<T>> it = allObjects.values().iterator(); while (it.hasNext()) { final PooledObject<T> pooledObject = it.next(); synchronized (pooledObject) { if (pooledObject.getState() == PooledObjectState.ALLOCATED && pooledObject.getLastUsedTime() <= timeout) { pooledObject.markAbandoned(); remove.add(pooledObject); } } } // Now remove the abandoned objects final Iterator<PooledObject<T>> itr = remove.iterator(); while (itr.hasNext()) { final PooledObject<T> pooledObject = itr.next(); if (ac.getLogAbandoned()) { pooledObject.printStackTrace(ac.getLogWriter()); } try { invalidateObject(pooledObject.getObject()); } catch (final Exception e) { e.printStackTrace(); } } } //--- Usage tracking support ----------------------------------------------- @Override public void use(final T pooledObject) { final AbandonedConfig ac = this.abandonedConfig; if (ac != null && ac.getUseUsageTracking()) { final PooledObject<T> wrapper = allObjects.get(new IdentityWrapper<>(pooledObject)); wrapper.use(); } } //--- JMX support ---------------------------------------------------------- private volatile String factoryType = null;
Returns an estimate of the number of threads currently blocked waiting for an object from the pool. This is intended for monitoring only, not for synchronization control.
Returns:The estimate of the number of threads currently blocked waiting for an object from the pool
/** * Returns an estimate of the number of threads currently blocked waiting for * an object from the pool. This is intended for monitoring only, not for * synchronization control. * * @return The estimate of the number of threads currently blocked waiting * for an object from the pool */
@Override public int getNumWaiters() { if (getBlockWhenExhausted()) { return idleObjects.getTakeQueueLength(); } return 0; }
Returns the type - including the specific type rather than the generic - of the factory.
Returns:A string representation of the factory type
/** * Returns the type - including the specific type rather than the generic - * of the factory. * * @return A string representation of the factory type */
@Override public String getFactoryType() { // Not thread safe. Accept that there may be multiple evaluations. if (factoryType == null) { final StringBuilder result = new StringBuilder(); result.append(factory.getClass().getName()); result.append('<'); final Class<?> pooledObjectType = PoolImplUtils.getFactoryType(factory.getClass()); result.append(pooledObjectType.getName()); result.append('>'); factoryType = result.toString(); } return factoryType; }
Provides information on all the objects in the pool, both idle (waiting to be borrowed) and active (currently borrowed).

Note: This is named listAllObjects so it is presented as an operation via JMX. That means it won't be invoked unless the explicitly requested whereas all attributes will be automatically requested when viewing the attributes for an object in a tool like JConsole.

Returns:Information grouped on all the objects in the pool
/** * Provides information on all the objects in the pool, both idle (waiting * to be borrowed) and active (currently borrowed). * <p> * Note: This is named listAllObjects so it is presented as an operation via * JMX. That means it won't be invoked unless the explicitly requested * whereas all attributes will be automatically requested when viewing the * attributes for an object in a tool like JConsole. * </p> * * @return Information grouped on all the objects in the pool */
@Override public Set<DefaultPooledObjectInfo> listAllObjects() { final Set<DefaultPooledObjectInfo> result = new HashSet<>(allObjects.size()); for (final PooledObject<T> p : allObjects.values()) { result.add(new DefaultPooledObjectInfo(p)); } return result; } // --- configuration attributes -------------------------------------------- private volatile int maxIdle = GenericObjectPoolConfig.DEFAULT_MAX_IDLE; private volatile int minIdle = GenericObjectPoolConfig.DEFAULT_MIN_IDLE; private final PooledObjectFactory<T> factory; // --- internal attributes ------------------------------------------------- /* * All of the objects currently associated with this pool in any state. It * excludes objects that have been destroyed. The size of * {@link #allObjects} will always be less than or equal to {@link * #_maxActive}. Map keys are pooled objects, values are the PooledObject * wrappers used internally by the pool. */ private final Map<IdentityWrapper<T>, PooledObject<T>> allObjects = new ConcurrentHashMap<>(); /* * The combined count of the currently created objects and those in the * process of being created. Under load, it may exceed {@link #_maxActive} * if multiple threads try and create a new object at the same time but * {@link #create()} will ensure that there are never more than * {@link #_maxActive} objects created at any one time. */ private final AtomicLong createCount = new AtomicLong(0); private long makeObjectCount = 0; private final Object makeObjectCountLock = new Object(); private final LinkedBlockingDeque<PooledObject<T>> idleObjects; // JMX specific attributes private static final String ONAME_BASE = "org.apache.commons.pool2:type=GenericObjectPool,name="; // Additional configuration properties for abandoned object tracking private volatile AbandonedConfig abandonedConfig = null; @Override protected void toStringAppendFields(final StringBuilder builder) { super.toStringAppendFields(builder); builder.append(", factoryType="); builder.append(factoryType); builder.append(", maxIdle="); builder.append(maxIdle); builder.append(", minIdle="); builder.append(minIdle); builder.append(", factory="); builder.append(factory); builder.append(", allObjects="); builder.append(allObjects); builder.append(", createCount="); builder.append(createCount); builder.append(", idleObjects="); builder.append(idleObjects); builder.append(", abandonedConfig="); builder.append(abandonedConfig); } }