org.apache.commons.pool.impl.GenericObjectPool Maven / Gradle / Ivy
/*
* 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.pool.impl;
import java.util.ArrayList;
import java.util.Collection;
import java.util.Iterator;
import java.util.LinkedList;
import java.util.List;
import java.util.NoSuchElementException;
import java.util.TimerTask;
import org.apache.commons.pool.BaseObjectPool;
import org.apache.commons.pool.ObjectPool;
import org.apache.commons.pool.PoolUtils;
import org.apache.commons.pool.PoolableObjectFactory;
import org.apache.commons.pool.impl.GenericKeyedObjectPool.ObjectTimestampPair;
/**
* A configurable {@link ObjectPool} implementation.
*
* When coupled with the appropriate {@link PoolableObjectFactory},
* GenericObjectPool provides robust pooling functionality for
* arbitrary objects.
*
* A GenericObjectPool provides a number of configurable parameters:
*
* -
* {@link #setMaxActive maxActive} controls the maximum number of
* objects that can be allocated by the pool (checked out to clients, or
* idle awaiting checkout) at a given time. When non-positive, there is no
* limit to the number of objects that can be managed by the pool at one time.
* When {@link #setMaxActive maxActive} is reached, the pool is said
* to be exhausted. The default setting for this parameter is 8.
*
* -
* {@link #setMaxIdle maxIdle} controls the maximum number of objects
* that can sit idle in the pool at any time. When negative, there is no
* limit to the number of objects that may be idle at one time. The default
* setting for this parameter is 8.
*
* -
* {@link #setWhenExhaustedAction whenExhaustedAction} specifies the
* behavior of the {@link #borrowObject} method when the pool is exhausted:
*
* -
* When {@link #setWhenExhaustedAction whenExhaustedAction} is
* {@link #WHEN_EXHAUSTED_FAIL}, {@link #borrowObject} will throw
* a {@link NoSuchElementException}
*
* -
* When {@link #setWhenExhaustedAction whenExhaustedAction} is
* {@link #WHEN_EXHAUSTED_GROW}, {@link #borrowObject} will create a new
* object and return it (essentially making {@link #setMaxActive maxActive}
* meaningless.)
*
* -
* When {@link #setWhenExhaustedAction whenExhaustedAction}
* is {@link #WHEN_EXHAUSTED_BLOCK}, {@link #borrowObject} will block
* (invoke {@link Object#wait()}) until a new or idle object is available.
* If a positive {@link #setMaxWait maxWait}
* value is supplied, then {@link #borrowObject} will block for at
* most that many milliseconds, after which a {@link NoSuchElementException}
* will be thrown. If {@link #setMaxWait maxWait} is non-positive,
* the {@link #borrowObject} method will block indefinitely.
*
*
* The default whenExhaustedAction
setting is
* {@link #WHEN_EXHAUSTED_BLOCK} and the default maxWait
* setting is -1. By default, therefore, borrowObject
will
* block indefinitely until an idle instance becomes available.
*
* -
* When {@link #setTestOnBorrow testOnBorrow} is set, the pool will
* attempt to validate each object before it is returned from the
* {@link #borrowObject} method. (Using the provided factory's
* {@link PoolableObjectFactory#validateObject} method.) Objects that fail
* to validate will be dropped from the pool, and a different object will
* be borrowed. The default setting for this parameter is
*
false.
*
* -
* When {@link #setTestOnReturn testOnReturn} is set, the pool will
* attempt to validate each object before it is returned to the pool in the
* {@link #returnObject} method. (Using the provided factory's
* {@link PoolableObjectFactory#validateObject}
* method.) Objects that fail to validate will be dropped from the pool.
* The default setting for this parameter is
false.
*
*
*
* 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 idle object eviction thread may be configured using the following
* attributes:
*
* -
* {@link #setTimeBetweenEvictionRunsMillis timeBetweenEvictionRunsMillis}
* indicates how long the eviction thread should sleep before "runs" of examining
* idle objects. When non-positive, no eviction thread will be launched. The
* default setting for this parameter is -1 (i.e., idle object eviction is
* disabled by default).
*
* -
* {@link #setMinEvictableIdleTimeMillis minEvictableIdleTimeMillis}
* specifies the minimum amount of time that an object may sit idle in the pool
* before it is eligible for eviction due to idle time. When non-positive, no object
* will be dropped from the pool due to idle time alone. This setting has no
* effect unless
timeBetweenEvictionRunsMillis > 0.
The default
* setting for this parameter is 30 minutes.
*
* -
* {@link #setTestWhileIdle testWhileIdle} indicates whether or not idle
* objects should be validated using the factory's
* {@link PoolableObjectFactory#validateObject} method. Objects that fail to
* validate will be dropped from the pool. This setting has no effect unless
*
timeBetweenEvictionRunsMillis > 0.
The default setting for
* this parameter is false.
*
* -
* {@link #setSoftMinEvictableIdleTimeMillis softMinEvictableIdleTimeMillis}
* specifies the minimum amount of time an object may sit idle in the pool
* before it is eligible for eviction by the idle object evictor
* (if any), with the extra condition that at least "minIdle" object instances
* remain in the pool. When non-positive, no objects will be evicted from the pool
* due to idle time alone. This setting has no effect unless
*
timeBetweenEvictionRunsMillis > 0.
and it is superceded by
* {@link #setMinEvictableIdleTimeMillis minEvictableIdleTimeMillis}
* (that is, if minEvictableIdleTimeMillis
is positive, then
* softMinEvictableIdleTimeMillis
is ignored). The default setting for
* this parameter is -1 (disabled).
*
* -
* {@link #setNumTestsPerEvictionRun numTestsPerEvictionRun}
* determines the number of objects examined in each run of the idle object
* evictor. This setting has no effect unless
*
timeBetweenEvictionRunsMillis > 0.
The default setting for
* this parameter is 3.
*
*
*
*
* The pool can be configured to behave as a LIFO queue with respect to idle
* objects - always returning the most recently used object from the pool,
* or as a FIFO queue, where borrowObject always returns the oldest object
* in the idle object pool.
*
* -
* {@link #setLifo lifo}
* determines whether or not the pool returns idle objects in
* last-in-first-out order. The default setting for this parameter is
*
true.
*
*
*
* GenericObjectPool is not usable without a {@link PoolableObjectFactory}. A
* non-null
factory must be provided either as a constructor argument
* or via a call to {@link #setFactory} before the pool is used.
*
* 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.
*
* @param the type of objects held in this pool
*
* @see GenericKeyedObjectPool
* @author Rodney Waldhoff
* @author Dirk Verbeeck
* @author Sandy McArthur
* @version $Revision: 1222396 $ $Date: 2011-12-22 14:02:25 -0500 (Thu, 22 Dec 2011) $
* @since Pool 1.0
*/
public class GenericObjectPool extends BaseObjectPool implements ObjectPool {
//--- public constants -------------------------------------------
/**
* A "when exhausted action" type indicating that when the pool is
* exhausted (i.e., the maximum number of active objects has
* been reached), the {@link #borrowObject}
* method should fail, throwing a {@link NoSuchElementException}.
* @see #WHEN_EXHAUSTED_BLOCK
* @see #WHEN_EXHAUSTED_GROW
* @see #setWhenExhaustedAction
*/
public static final byte WHEN_EXHAUSTED_FAIL = 0;
/**
* A "when exhausted action" type indicating that when the pool
* is exhausted (i.e., the maximum number
* of active objects has been reached), the {@link #borrowObject}
* method should block until a new object is available, or the
* {@link #getMaxWait maximum wait time} has been reached.
* @see #WHEN_EXHAUSTED_FAIL
* @see #WHEN_EXHAUSTED_GROW
* @see #setMaxWait
* @see #getMaxWait
* @see #setWhenExhaustedAction
*/
public static final byte WHEN_EXHAUSTED_BLOCK = 1;
/**
* A "when exhausted action" type indicating that when the pool is
* exhausted (i.e., the maximum number
* of active objects has been reached), the {@link #borrowObject}
* method should simply create a new object anyway.
* @see #WHEN_EXHAUSTED_FAIL
* @see #WHEN_EXHAUSTED_GROW
* @see #setWhenExhaustedAction
*/
public static final byte WHEN_EXHAUSTED_GROW = 2;
/**
* The default cap on the number of "sleeping" instances in the pool.
* @see #getMaxIdle
* @see #setMaxIdle
*/
public static final int DEFAULT_MAX_IDLE = 8;
/**
* The default minimum number of "sleeping" instances in the pool
* before before the evictor thread (if active) spawns new objects.
* @see #getMinIdle
* @see #setMinIdle
*/
public static final int DEFAULT_MIN_IDLE = 0;
/**
* The default cap on the total number of active instances from the pool.
* @see #getMaxActive
*/
public static final int DEFAULT_MAX_ACTIVE = 8;
/**
* The default "when exhausted action" for the pool.
* @see #WHEN_EXHAUSTED_BLOCK
* @see #WHEN_EXHAUSTED_FAIL
* @see #WHEN_EXHAUSTED_GROW
* @see #setWhenExhaustedAction
*/
public static final byte DEFAULT_WHEN_EXHAUSTED_ACTION = WHEN_EXHAUSTED_BLOCK;
/**
* The default LIFO status. True means that borrowObject returns the
* most recently used ("last in") idle object in the pool (if there are
* idle instances available). False means that the pool behaves as a FIFO
* queue - objects are taken from the idle object pool in the order that
* they are returned to the pool.
* @see #setLifo
* @since 1.4
*/
public static final boolean DEFAULT_LIFO = true;
/**
* The default maximum amount of time (in milliseconds) the
* {@link #borrowObject} method should block before throwing
* an exception when the pool is exhausted and the
* {@link #getWhenExhaustedAction "when exhausted" action} is
* {@link #WHEN_EXHAUSTED_BLOCK}.
* @see #getMaxWait
* @see #setMaxWait
*/
public static final long DEFAULT_MAX_WAIT = -1L;
/**
* The default "test on borrow" value.
* @see #getTestOnBorrow
* @see #setTestOnBorrow
*/
public static final boolean DEFAULT_TEST_ON_BORROW = false;
/**
* The default "test on return" value.
* @see #getTestOnReturn
* @see #setTestOnReturn
*/
public static final boolean DEFAULT_TEST_ON_RETURN = false;
/**
* The default "test while idle" value.
* @see #getTestWhileIdle
* @see #setTestWhileIdle
* @see #getTimeBetweenEvictionRunsMillis
* @see #setTimeBetweenEvictionRunsMillis
*/
public static final boolean DEFAULT_TEST_WHILE_IDLE = false;
/**
* The default "time between eviction runs" value.
* @see #getTimeBetweenEvictionRunsMillis
* @see #setTimeBetweenEvictionRunsMillis
*/
public static final long DEFAULT_TIME_BETWEEN_EVICTION_RUNS_MILLIS = -1L;
/**
* The default number of objects to examine per run in the
* idle object evictor.
* @see #getNumTestsPerEvictionRun
* @see #setNumTestsPerEvictionRun
* @see #getTimeBetweenEvictionRunsMillis
* @see #setTimeBetweenEvictionRunsMillis
*/
public static final int DEFAULT_NUM_TESTS_PER_EVICTION_RUN = 3;
/**
* The default value for {@link #getMinEvictableIdleTimeMillis}.
* @see #getMinEvictableIdleTimeMillis
* @see #setMinEvictableIdleTimeMillis
*/
public static final long DEFAULT_MIN_EVICTABLE_IDLE_TIME_MILLIS = 1000L * 60L * 30L;
/**
* The default value for {@link #getSoftMinEvictableIdleTimeMillis}.
* @see #getSoftMinEvictableIdleTimeMillis
* @see #setSoftMinEvictableIdleTimeMillis
*/
public static final long DEFAULT_SOFT_MIN_EVICTABLE_IDLE_TIME_MILLIS = -1;
//--- constructors -----------------------------------------------
/**
* Create a new GenericObjectPool with default properties.
*/
public GenericObjectPool() {
this(null, DEFAULT_MAX_ACTIVE, DEFAULT_WHEN_EXHAUSTED_ACTION, DEFAULT_MAX_WAIT, DEFAULT_MAX_IDLE,
DEFAULT_MIN_IDLE, DEFAULT_TEST_ON_BORROW, DEFAULT_TEST_ON_RETURN, DEFAULT_TIME_BETWEEN_EVICTION_RUNS_MILLIS,
DEFAULT_NUM_TESTS_PER_EVICTION_RUN, DEFAULT_MIN_EVICTABLE_IDLE_TIME_MILLIS, DEFAULT_TEST_WHILE_IDLE);
}
/**
* Create a new GenericObjectPool using the specified factory.
* @param factory the (possibly null)PoolableObjectFactory to use to create, validate and destroy objects
*/
public GenericObjectPool(PoolableObjectFactory factory) {
this(factory, DEFAULT_MAX_ACTIVE, DEFAULT_WHEN_EXHAUSTED_ACTION, DEFAULT_MAX_WAIT, DEFAULT_MAX_IDLE,
DEFAULT_MIN_IDLE, DEFAULT_TEST_ON_BORROW, DEFAULT_TEST_ON_RETURN, DEFAULT_TIME_BETWEEN_EVICTION_RUNS_MILLIS,
DEFAULT_NUM_TESTS_PER_EVICTION_RUN, DEFAULT_MIN_EVICTABLE_IDLE_TIME_MILLIS, DEFAULT_TEST_WHILE_IDLE);
}
/**
* Create a new GenericObjectPool using the specified values.
* @param factory the (possibly null)PoolableObjectFactory to use to create, validate and destroy objects
* @param config a non-null {@link GenericObjectPool.Config} describing my configuration
*/
public GenericObjectPool(PoolableObjectFactory factory, GenericObjectPool.Config config) {
this(factory, config.maxActive, config.whenExhaustedAction, config.maxWait, config.maxIdle, config.minIdle,
config.testOnBorrow, config.testOnReturn, config.timeBetweenEvictionRunsMillis,
config.numTestsPerEvictionRun, config.minEvictableIdleTimeMillis, config.testWhileIdle,
config.softMinEvictableIdleTimeMillis, config.lifo);
}
/**
* Create a new GenericObjectPool using the specified values.
* @param factory the (possibly null)PoolableObjectFactory to use to create, validate and destroy objects
* @param maxActive the maximum number of objects that can be borrowed from me at one time (see {@link #setMaxActive})
*/
public GenericObjectPool(PoolableObjectFactory factory, int maxActive) {
this(factory, maxActive, DEFAULT_WHEN_EXHAUSTED_ACTION, DEFAULT_MAX_WAIT, DEFAULT_MAX_IDLE, DEFAULT_MIN_IDLE,
DEFAULT_TEST_ON_BORROW, DEFAULT_TEST_ON_RETURN, DEFAULT_TIME_BETWEEN_EVICTION_RUNS_MILLIS,
DEFAULT_NUM_TESTS_PER_EVICTION_RUN, DEFAULT_MIN_EVICTABLE_IDLE_TIME_MILLIS, DEFAULT_TEST_WHILE_IDLE);
}
/**
* Create a new GenericObjectPool using the specified values.
* @param factory the (possibly null)PoolableObjectFactory to use to create, validate and destroy objects
* @param maxActive the maximum number of objects that can be borrowed from me at one time (see {@link #setMaxActive})
* @param whenExhaustedAction the action to take when the pool is exhausted (see {@link #getWhenExhaustedAction})
* @param maxWait the maximum amount of time to wait for an idle object when the pool is exhausted an and
* whenExhaustedAction is {@link #WHEN_EXHAUSTED_BLOCK} (otherwise ignored) (see {@link #getMaxWait})
*/
public GenericObjectPool(PoolableObjectFactory factory, int maxActive, byte whenExhaustedAction, long maxWait) {
this(factory, maxActive, whenExhaustedAction, maxWait, DEFAULT_MAX_IDLE, DEFAULT_MIN_IDLE, DEFAULT_TEST_ON_BORROW,
DEFAULT_TEST_ON_RETURN, DEFAULT_TIME_BETWEEN_EVICTION_RUNS_MILLIS, DEFAULT_NUM_TESTS_PER_EVICTION_RUN,
DEFAULT_MIN_EVICTABLE_IDLE_TIME_MILLIS, DEFAULT_TEST_WHILE_IDLE);
}
/**
* Create a new GenericObjectPool using the specified values.
* @param factory the (possibly null)PoolableObjectFactory to use to create, validate and destroy objects
* @param maxActive the maximum number of objects that can be borrowed at one time (see {@link #setMaxActive})
* @param whenExhaustedAction the action to take when the pool is exhausted (see {@link #getWhenExhaustedAction})
* @param maxWait the maximum amount of time to wait for an idle object when the pool is exhausted an and
* whenExhaustedAction is {@link #WHEN_EXHAUSTED_BLOCK} (otherwise ignored) (see {@link #getMaxWait})
* @param testOnBorrow whether or not to validate objects before they are returned by the {@link #borrowObject} method
* (see {@link #getTestOnBorrow})
* @param testOnReturn whether or not to validate objects after they are returned to the {@link #returnObject} method
* (see {@link #getTestOnReturn})
*/
public GenericObjectPool(PoolableObjectFactory factory, int maxActive, byte whenExhaustedAction, long maxWait,
boolean testOnBorrow, boolean testOnReturn) {
this(factory, maxActive, whenExhaustedAction, maxWait, DEFAULT_MAX_IDLE, DEFAULT_MIN_IDLE, testOnBorrow,
testOnReturn, DEFAULT_TIME_BETWEEN_EVICTION_RUNS_MILLIS, DEFAULT_NUM_TESTS_PER_EVICTION_RUN,
DEFAULT_MIN_EVICTABLE_IDLE_TIME_MILLIS, DEFAULT_TEST_WHILE_IDLE);
}
/**
* Create a new GenericObjectPool using the specified values.
* @param factory the (possibly null)PoolableObjectFactory to use to create, validate and destroy objects
* @param maxActive the maximum number of objects that can be borrowed at one time (see {@link #setMaxActive})
* @param whenExhaustedAction the action to take when the pool is exhausted (see {@link #getWhenExhaustedAction})
* @param maxWait the maximum amount of time to wait for an idle object when the pool is exhausted and
* whenExhaustedAction is {@link #WHEN_EXHAUSTED_BLOCK} (otherwise ignored) (see {@link #getMaxWait})
* @param maxIdle the maximum number of idle objects in my pool (see {@link #getMaxIdle})
*/
public GenericObjectPool(PoolableObjectFactory factory, int maxActive, byte whenExhaustedAction, long maxWait, int maxIdle) {
this(factory, maxActive, whenExhaustedAction, maxWait, maxIdle, DEFAULT_MIN_IDLE, DEFAULT_TEST_ON_BORROW,
DEFAULT_TEST_ON_RETURN, DEFAULT_TIME_BETWEEN_EVICTION_RUNS_MILLIS, DEFAULT_NUM_TESTS_PER_EVICTION_RUN,
DEFAULT_MIN_EVICTABLE_IDLE_TIME_MILLIS, DEFAULT_TEST_WHILE_IDLE);
}
/**
* Create a new GenericObjectPool using the specified values.
* @param factory the (possibly null)PoolableObjectFactory to use to create, validate and destroy objects
* @param maxActive the maximum number of objects that can be borrowed at one time (see {@link #setMaxActive})
* @param whenExhaustedAction the action to take when the pool is exhausted (see {@link #getWhenExhaustedAction})
* @param maxWait the maximum amount of time to wait for an idle object when the pool is exhausted and
* whenExhaustedAction is {@link #WHEN_EXHAUSTED_BLOCK} (otherwise ignored) (see {@link #getMaxWait})
* @param maxIdle the maximum number of idle objects in my pool (see {@link #getMaxIdle})
* @param testOnBorrow whether or not to validate objects before they are returned by the {@link #borrowObject} method
* (see {@link #getTestOnBorrow})
* @param testOnReturn whether or not to validate objects after they are returned to the {@link #returnObject} method
* (see {@link #getTestOnReturn})
*/
public GenericObjectPool(PoolableObjectFactory factory, int maxActive, byte whenExhaustedAction, long maxWait,
int maxIdle, boolean testOnBorrow, boolean testOnReturn) {
this(factory, maxActive, whenExhaustedAction, maxWait, maxIdle, DEFAULT_MIN_IDLE, testOnBorrow, testOnReturn,
DEFAULT_TIME_BETWEEN_EVICTION_RUNS_MILLIS, DEFAULT_NUM_TESTS_PER_EVICTION_RUN,
DEFAULT_MIN_EVICTABLE_IDLE_TIME_MILLIS, DEFAULT_TEST_WHILE_IDLE);
}
/**
* Create a new GenericObjectPool using the specified values.
* @param factory the (possibly null)PoolableObjectFactory to use to create, validate and destroy objects
* @param maxActive the maximum number of objects that can be borrowed at one time (see {@link #setMaxActive})
* @param whenExhaustedAction the action to take when the pool is exhausted (see {@link #setWhenExhaustedAction})
* @param maxWait the maximum amount of time to wait for an idle object when the pool is exhausted and
* whenExhaustedAction is {@link #WHEN_EXHAUSTED_BLOCK} (otherwise ignored) (see {@link #setMaxWait})
* @param maxIdle the maximum number of idle objects in my pool (see {@link #setMaxIdle})
* @param testOnBorrow whether or not to validate objects before they are returned by the {@link #borrowObject}
* method (see {@link #setTestOnBorrow})
* @param testOnReturn whether or not to validate objects after they are returned to the {@link #returnObject} method
* (see {@link #setTestOnReturn})
* @param timeBetweenEvictionRunsMillis the amount of time (in milliseconds) to sleep between examining idle objects
* for eviction (see {@link #setTimeBetweenEvictionRunsMillis})
* @param numTestsPerEvictionRun the number of idle objects to examine per run within the idle object eviction thread
* (if any) (see {@link #setNumTestsPerEvictionRun})
* @param minEvictableIdleTimeMillis the minimum number of milliseconds an object can sit idle in the pool before it
* is eligible for eviction (see {@link #setMinEvictableIdleTimeMillis})
* @param testWhileIdle whether or not to validate objects in the idle object eviction thread, if any
* (see {@link #setTestWhileIdle})
*/
public GenericObjectPool(PoolableObjectFactory factory, int maxActive, byte whenExhaustedAction, long maxWait,
int maxIdle, boolean testOnBorrow, boolean testOnReturn, long timeBetweenEvictionRunsMillis,
int numTestsPerEvictionRun, long minEvictableIdleTimeMillis, boolean testWhileIdle) {
this(factory, maxActive, whenExhaustedAction, maxWait, maxIdle, DEFAULT_MIN_IDLE, testOnBorrow, testOnReturn,
timeBetweenEvictionRunsMillis, numTestsPerEvictionRun, minEvictableIdleTimeMillis, testWhileIdle);
}
/**
* Create a new GenericObjectPool using the specified values.
* @param factory the (possibly null)PoolableObjectFactory to use to create, validate and destroy objects
* @param maxActive the maximum number of objects that can be borrowed at one time (see {@link #setMaxActive})
* @param whenExhaustedAction the action to take when the pool is exhausted (see {@link #setWhenExhaustedAction})
* @param maxWait the maximum amount of time to wait for an idle object when the pool is exhausted and
* whenExhaustedAction is {@link #WHEN_EXHAUSTED_BLOCK} (otherwise ignored) (see {@link #setMaxWait})
* @param maxIdle the maximum number of idle objects in my pool (see {@link #setMaxIdle})
* @param minIdle the minimum number of idle objects in my pool (see {@link #setMinIdle})
* @param testOnBorrow whether or not to validate objects before they are returned by the {@link #borrowObject} method
* (see {@link #setTestOnBorrow})
* @param testOnReturn whether or not to validate objects after they are returned to the {@link #returnObject} method
* (see {@link #setTestOnReturn})
* @param timeBetweenEvictionRunsMillis the amount of time (in milliseconds) to sleep between examining idle objects
* for eviction (see {@link #setTimeBetweenEvictionRunsMillis})
* @param numTestsPerEvictionRun the number of idle objects to examine per run within the idle object eviction thread
* (if any) (see {@link #setNumTestsPerEvictionRun})
* @param minEvictableIdleTimeMillis the minimum number of milliseconds an object can sit idle in the pool before
* it is eligible for eviction (see {@link #setMinEvictableIdleTimeMillis})
* @param testWhileIdle whether or not to validate objects in the idle object eviction thread, if any
* (see {@link #setTestWhileIdle})
*/
public GenericObjectPool(PoolableObjectFactory factory, int maxActive, byte whenExhaustedAction, long maxWait,
int maxIdle, int minIdle, boolean testOnBorrow, boolean testOnReturn, long timeBetweenEvictionRunsMillis,
int numTestsPerEvictionRun, long minEvictableIdleTimeMillis, boolean testWhileIdle) {
this(factory, maxActive, whenExhaustedAction, maxWait, maxIdle, minIdle, testOnBorrow, testOnReturn,
timeBetweenEvictionRunsMillis, numTestsPerEvictionRun, minEvictableIdleTimeMillis, testWhileIdle,
DEFAULT_SOFT_MIN_EVICTABLE_IDLE_TIME_MILLIS);
}
/**
* Create a new GenericObjectPool using the specified values.
* @param factory the (possibly null)PoolableObjectFactory to use to create, validate and destroy objects
* @param maxActive the maximum number of objects that can be borrowed at one time (see {@link #setMaxActive})
* @param whenExhaustedAction the action to take when the pool is exhausted (see {@link #setWhenExhaustedAction})
* @param maxWait the maximum amount of time to wait for an idle object when the pool is exhausted and
* whenExhaustedAction is {@link #WHEN_EXHAUSTED_BLOCK} (otherwise ignored) (see {@link #setMaxWait})
* @param maxIdle the maximum number of idle objects in my pool (see {@link #setMaxIdle})
* @param minIdle the minimum number of idle objects in my pool (see {@link #setMinIdle})
* @param testOnBorrow whether or not to validate objects before they are returned by the {@link #borrowObject}
* method (see {@link #setTestOnBorrow})
* @param testOnReturn whether or not to validate objects after they are returned to the {@link #returnObject}
* method (see {@link #setTestOnReturn})
* @param timeBetweenEvictionRunsMillis the amount of time (in milliseconds) to sleep between examining idle objects
* for eviction (see {@link #setTimeBetweenEvictionRunsMillis})
* @param numTestsPerEvictionRun the number of idle objects to examine per run within the idle object eviction thread
* (if any) (see {@link #setNumTestsPerEvictionRun})
* @param minEvictableIdleTimeMillis the minimum number of milliseconds an object can sit idle in the pool before
* it is eligible for eviction (see {@link #setMinEvictableIdleTimeMillis})
* @param testWhileIdle whether or not to validate objects in the idle object eviction thread, if any
* (see {@link #setTestWhileIdle})
* @param softMinEvictableIdleTimeMillis the minimum number of milliseconds an object can sit idle in the pool before it is
* eligible for eviction with the extra condition that at least "minIdle" amount of object remain in the pool.
* (see {@link #setSoftMinEvictableIdleTimeMillis})
* @since Pool 1.3
*/
public GenericObjectPool(PoolableObjectFactory factory, int maxActive, byte whenExhaustedAction, long maxWait,
int maxIdle, int minIdle, boolean testOnBorrow, boolean testOnReturn, long timeBetweenEvictionRunsMillis,
int numTestsPerEvictionRun, long minEvictableIdleTimeMillis, boolean testWhileIdle,
long softMinEvictableIdleTimeMillis) {
this(factory, maxActive, whenExhaustedAction, maxWait, maxIdle, minIdle, testOnBorrow, testOnReturn,
timeBetweenEvictionRunsMillis, numTestsPerEvictionRun, minEvictableIdleTimeMillis, testWhileIdle,
softMinEvictableIdleTimeMillis, DEFAULT_LIFO);
}
/**
* Create a new GenericObjectPool using the specified values.
* @param factory the (possibly null)PoolableObjectFactory to use to create, validate and destroy objects
* @param maxActive the maximum number of objects that can be borrowed at one time (see {@link #setMaxActive})
* @param whenExhaustedAction the action to take when the pool is exhausted (see {@link #setWhenExhaustedAction})
* @param maxWait the maximum amount of time to wait for an idle object when the pool is exhausted and
* whenExhaustedAction is {@link #WHEN_EXHAUSTED_BLOCK} (otherwise ignored) (see {@link #setMaxWait})
* @param maxIdle the maximum number of idle objects in my pool (see {@link #setMaxIdle})
* @param minIdle the minimum number of idle objects in my pool (see {@link #setMinIdle})
* @param testOnBorrow whether or not to validate objects before they are returned by the {@link #borrowObject}
* method (see {@link #setTestOnBorrow})
* @param testOnReturn whether or not to validate objects after they are returned to the {@link #returnObject}
* method (see {@link #setTestOnReturn})
* @param timeBetweenEvictionRunsMillis the amount of time (in milliseconds) to sleep between examining idle
* objects for eviction (see {@link #setTimeBetweenEvictionRunsMillis})
* @param numTestsPerEvictionRun the number of idle objects to examine per run within the idle object eviction
* thread (if any) (see {@link #setNumTestsPerEvictionRun})
* @param minEvictableIdleTimeMillis the minimum number of milliseconds an object can sit idle in the pool before
* it is eligible for eviction (see {@link #setMinEvictableIdleTimeMillis})
* @param testWhileIdle whether or not to validate objects in the idle object eviction thread, if any
* (see {@link #setTestWhileIdle})
* @param softMinEvictableIdleTimeMillis the minimum number of milliseconds an object can sit idle in the
* pool before it is eligible for eviction with the extra condition that at least "minIdle" amount of object
* remain in the pool. (see {@link #setSoftMinEvictableIdleTimeMillis})
* @param lifo whether or not objects are returned in last-in-first-out order from the idle object pool
* (see {@link #setLifo})
* @since Pool 1.4
*/
public GenericObjectPool(PoolableObjectFactory factory, int maxActive, byte whenExhaustedAction, long maxWait,
int maxIdle, int minIdle, boolean testOnBorrow, boolean testOnReturn, long timeBetweenEvictionRunsMillis,
int numTestsPerEvictionRun, long minEvictableIdleTimeMillis, boolean testWhileIdle,
long softMinEvictableIdleTimeMillis, boolean lifo) {
_factory = factory;
_maxActive = maxActive;
_lifo = lifo;
switch(whenExhaustedAction) {
case WHEN_EXHAUSTED_BLOCK:
case WHEN_EXHAUSTED_FAIL:
case WHEN_EXHAUSTED_GROW:
_whenExhaustedAction = whenExhaustedAction;
break;
default:
throw new IllegalArgumentException("whenExhaustedAction " + whenExhaustedAction + " not recognized.");
}
_maxWait = maxWait;
_maxIdle = maxIdle;
_minIdle = minIdle;
_testOnBorrow = testOnBorrow;
_testOnReturn = testOnReturn;
_timeBetweenEvictionRunsMillis = timeBetweenEvictionRunsMillis;
_numTestsPerEvictionRun = numTestsPerEvictionRun;
_minEvictableIdleTimeMillis = minEvictableIdleTimeMillis;
_softMinEvictableIdleTimeMillis = softMinEvictableIdleTimeMillis;
_testWhileIdle = testWhileIdle;
_pool = new CursorableLinkedList>();
startEvictor(_timeBetweenEvictionRunsMillis);
}
//--- public methods ---------------------------------------------
//--- configuration methods --------------------------------------
/**
* Returns the maximum number of objects that can be allocated by the pool
* (checked out to clients, or idle awaiting checkout) at a given time.
* When non-positive, there is no limit to the number of objects that can
* be managed by the pool at one time.
*
* @return the cap on the total number of object instances managed by the pool.
* @see #setMaxActive
*/
public synchronized int getMaxActive() {
return _maxActive;
}
/**
* Sets the cap on the number of objects that can be allocated by the pool
* (checked out to clients, or idle awaiting checkout) at a given time. Use
* a negative value for no limit.
*
* @param maxActive The cap on the total number of object instances managed by the pool.
* Negative values mean that there is no limit to the number of objects allocated
* by the pool.
* @see #getMaxActive
*/
public void setMaxActive(int maxActive) {
synchronized(this) {
_maxActive = maxActive;
}
allocate();
}
/**
* Returns the action to take when the {@link #borrowObject} method
* is invoked when the pool is exhausted (the maximum number
* of "active" objects has been reached).
*
* @return one of {@link #WHEN_EXHAUSTED_BLOCK}, {@link #WHEN_EXHAUSTED_FAIL} or {@link #WHEN_EXHAUSTED_GROW}
* @see #setWhenExhaustedAction
*/
public synchronized byte getWhenExhaustedAction() {
return _whenExhaustedAction;
}
/**
* Sets the action to take when the {@link #borrowObject} method
* is invoked when the pool is exhausted (the maximum number
* of "active" objects has been reached).
*
* @param whenExhaustedAction the action code, which must be one of
* {@link #WHEN_EXHAUSTED_BLOCK}, {@link #WHEN_EXHAUSTED_FAIL},
* or {@link #WHEN_EXHAUSTED_GROW}
* @see #getWhenExhaustedAction
*/
public void setWhenExhaustedAction(byte whenExhaustedAction) {
synchronized(this) {
switch(whenExhaustedAction) {
case WHEN_EXHAUSTED_BLOCK:
case WHEN_EXHAUSTED_FAIL:
case WHEN_EXHAUSTED_GROW:
_whenExhaustedAction = whenExhaustedAction;
break;
default:
throw new IllegalArgumentException("whenExhaustedAction " + whenExhaustedAction + " not recognized.");
}
}
allocate();
}
/**
* Returns the maximum amount of time (in milliseconds) the
* {@link #borrowObject} method should block before throwing
* an exception when the pool is exhausted and the
* {@link #setWhenExhaustedAction "when exhausted" action} is
* {@link #WHEN_EXHAUSTED_BLOCK}.
*
* When less than or equal to 0, the {@link #borrowObject} method
* may block indefinitely.
*
* @return maximum number of milliseconds to block when borrowing an object.
* @see #setMaxWait
* @see #setWhenExhaustedAction
* @see #WHEN_EXHAUSTED_BLOCK
*/
public synchronized long getMaxWait() {
return _maxWait;
}
/**
* Sets the maximum amount of time (in milliseconds) the
* {@link #borrowObject} method should block before throwing
* an exception when the pool is exhausted and the
* {@link #setWhenExhaustedAction "when exhausted" action} is
* {@link #WHEN_EXHAUSTED_BLOCK}.
*
* When less than or equal to 0, the {@link #borrowObject} method
* may block indefinitely.
*
* @param maxWait maximum number of milliseconds to block when borrowing an object.
* @see #getMaxWait
* @see #setWhenExhaustedAction
* @see #WHEN_EXHAUSTED_BLOCK
*/
public void setMaxWait(long maxWait) {
synchronized(this) {
_maxWait = maxWait;
}
allocate();
}
/**
* Returns the cap on the number of "idle" instances in the pool.
* @return the cap on the number of "idle" instances in the pool.
* @see #setMaxIdle
*/
public synchronized int getMaxIdle() {
return _maxIdle;
}
/**
* Sets 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 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(int maxIdle) {
synchronized(this) {
_maxIdle = maxIdle;
}
allocate();
}
/**
* Sets the minimum number of objects allowed in the pool
* before the evictor thread (if active) spawns new objects.
* Note that no objects are created when
* numActive + numIdle >= maxActive.
* This setting has no effect if the idle object evictor is disabled
* (i.e. if timeBetweenEvictionRunsMillis <= 0
).
*
* @param minIdle The minimum number of objects.
* @see #getMinIdle
* @see #getTimeBetweenEvictionRunsMillis()
*/
public void setMinIdle(int minIdle) {
synchronized(this) {
_minIdle = minIdle;
}
allocate();
}
/**
* Returns the minimum number of objects allowed in the pool
* before the evictor thread (if active) spawns new objects.
* (Note no objects are created when: numActive + numIdle >= maxActive)
*
* @return The minimum number of objects.
* @see #setMinIdle
*/
public synchronized int getMinIdle() {
return _minIdle;
}
/**
* When true, objects will be
* {@link PoolableObjectFactory#validateObject validated}
* before being returned by the {@link #borrowObject}
* method. If the object fails to validate,
* it will be dropped from the pool, and we will attempt
* to borrow another.
*
* @return true
if objects are validated before being borrowed.
* @see #setTestOnBorrow
*/
public boolean getTestOnBorrow() {
return _testOnBorrow;
}
/**
* When true, objects will be
* {@link PoolableObjectFactory#validateObject validated}
* before being returned by the {@link #borrowObject}
* method. If the object fails to validate,
* it will be dropped from the pool, and we will attempt
* to borrow another.
*
* @param testOnBorrow true
if objects should be validated before being borrowed.
* @see #getTestOnBorrow
*/
public void setTestOnBorrow(boolean testOnBorrow) {
_testOnBorrow = testOnBorrow;
}
/**
* When true, objects will be
* {@link PoolableObjectFactory#validateObject validated}
* before being returned to the pool within the
* {@link #returnObject}.
*
* @return true
when objects will be validated after returned to {@link #returnObject}.
* @see #setTestOnReturn
*/
public boolean getTestOnReturn() {
return _testOnReturn;
}
/**
* When true, objects will be
* {@link PoolableObjectFactory#validateObject validated}
* before being returned to the pool within the
* {@link #returnObject}.
*
* @param testOnReturn true
so objects will be validated after returned to {@link #returnObject}.
* @see #getTestOnReturn
*/
public void setTestOnReturn(boolean testOnReturn) {
_testOnReturn = testOnReturn;
}
/**
* Returns the number of milliseconds to sleep between runs of the
* idle object evictor thread.
* When non-positive, no idle object evictor thread will be
* run.
*
* @return number of milliseconds to sleep between evictor runs.
* @see #setTimeBetweenEvictionRunsMillis
*/
public synchronized long getTimeBetweenEvictionRunsMillis() {
return _timeBetweenEvictionRunsMillis;
}
/**
* Sets the number of milliseconds to sleep between runs of the
* idle object evictor thread.
* When non-positive, no idle object evictor thread will be
* run.
*
* @param timeBetweenEvictionRunsMillis number of milliseconds to sleep between evictor runs.
* @see #getTimeBetweenEvictionRunsMillis
*/
public synchronized void setTimeBetweenEvictionRunsMillis(long timeBetweenEvictionRunsMillis) {
_timeBetweenEvictionRunsMillis = timeBetweenEvictionRunsMillis;
startEvictor(_timeBetweenEvictionRunsMillis);
}
/**
* Returns the max number of objects to examine during each run of the
* idle object evictor thread (if any).
*
* @return max number of objects to examine during each evictor run.
* @see #setNumTestsPerEvictionRun
* @see #setTimeBetweenEvictionRunsMillis
*/
public synchronized int getNumTestsPerEvictionRun() {
return _numTestsPerEvictionRun;
}
/**
* Sets the max number of objects to examine during each run of the
* idle object evictor thread (if any).
*
* When a negative value is supplied, ceil({@link #getNumIdle})/abs({@link #getNumTestsPerEvictionRun})
* tests will be run. That is, when the value is -n, roughly one nth of the
* idle objects will be tested per run. When the value is positive, the number of tests
* actually performed in each run will be the minimum of this value and the number of instances
* idle in the pool.
*
* @param numTestsPerEvictionRun max number of objects to examine during each evictor run.
* @see #getNumTestsPerEvictionRun
* @see #setTimeBetweenEvictionRunsMillis
*/
public synchronized void setNumTestsPerEvictionRun(int numTestsPerEvictionRun) {
_numTestsPerEvictionRun = numTestsPerEvictionRun;
}
/**
* Returns the minimum amount of time an object may sit idle in the pool
* before it is eligible for eviction by the idle object evictor
* (if any).
*
* @return minimum amount of time an object may sit idle in the pool before it is eligible for eviction.
* @see #setMinEvictableIdleTimeMillis
* @see #setTimeBetweenEvictionRunsMillis
*/
public synchronized long getMinEvictableIdleTimeMillis() {
return _minEvictableIdleTimeMillis;
}
/**
* Sets the minimum amount of time an object may sit idle in the pool
* before it is eligible for eviction by the idle object evictor
* (if any).
* When non-positive, no objects will be evicted from the pool
* due to idle time alone.
* @param minEvictableIdleTimeMillis minimum amount of time an object may sit idle in the pool before
* it is eligible for eviction.
* @see #getMinEvictableIdleTimeMillis
* @see #setTimeBetweenEvictionRunsMillis
*/
public synchronized void setMinEvictableIdleTimeMillis(long minEvictableIdleTimeMillis) {
_minEvictableIdleTimeMillis = minEvictableIdleTimeMillis;
}
/**
* Returns the minimum amount of time an object may sit idle in the pool
* before it is eligible for eviction by the idle object evictor
* (if any), with the extra condition that at least
* "minIdle" amount of object remain in the pool.
*
* @return minimum amount of time an object may sit idle in the pool before it is eligible for eviction.
* @since Pool 1.3
* @see #setSoftMinEvictableIdleTimeMillis
*/
public synchronized long getSoftMinEvictableIdleTimeMillis() {
return _softMinEvictableIdleTimeMillis;
}
/**
* Sets the minimum amount of time an object may sit idle in the pool
* before it is eligible for eviction by the idle object evictor
* (if any), with the extra condition that at least
* "minIdle" object instances remain in the pool.
* When non-positive, no objects will be evicted from the pool
* due to idle time alone.
*
* @param softMinEvictableIdleTimeMillis minimum amount of time an object may sit idle in the pool before
* it is eligible for eviction.
* @since Pool 1.3
* @see #getSoftMinEvictableIdleTimeMillis
*/
public synchronized void setSoftMinEvictableIdleTimeMillis(long softMinEvictableIdleTimeMillis) {
_softMinEvictableIdleTimeMillis = softMinEvictableIdleTimeMillis;
}
/**
* When true, objects will be
* {@link PoolableObjectFactory#validateObject validated}
* by the idle object evictor (if any). If an object
* fails to validate, it will be dropped from the pool.
*
* @return true
when objects will be validated by the evictor.
* @see #setTestWhileIdle
* @see #setTimeBetweenEvictionRunsMillis
*/
public synchronized boolean getTestWhileIdle() {
return _testWhileIdle;
}
/**
* When true, objects will be
* {@link PoolableObjectFactory#validateObject validated}
* by the idle object evictor (if any). If an object
* fails to validate, it will be dropped from the pool.
*
* @param testWhileIdle true
so objects will be validated by the evictor.
* @see #getTestWhileIdle
* @see #setTimeBetweenEvictionRunsMillis
*/
public synchronized void setTestWhileIdle(boolean testWhileIdle) {
_testWhileIdle = testWhileIdle;
}
/**
* Whether or not the idle object pool acts as a LIFO queue. True means
* that borrowObject returns the most recently used ("last in") idle object
* in the pool (if there are idle instances available). False means that
* the pool behaves as a FIFO queue - objects are taken from the idle object
* pool in the order that they are returned to the pool.
*
* @return true if the pool is configured to act as a LIFO queue
* @since 1.4
*/
public synchronized boolean getLifo() {
return _lifo;
}
/**
* Sets the LIFO property of the pool. True means that borrowObject returns
* the most recently used ("last in") idle object in the pool (if there are
* idle instances available). False means that the pool behaves as a FIFO
* queue - objects are taken from the idle object pool in the order that
* they are returned to the pool.
*
* @param lifo the new value for the LIFO property
* @since 1.4
*/
public synchronized void setLifo(boolean lifo) {
this._lifo = lifo;
}
/**
* Sets my configuration.
*
* @param conf configuration to use.
* @see GenericObjectPool.Config
*/
public void setConfig(GenericObjectPool.Config conf) {
synchronized (this) {
setMaxIdle(conf.maxIdle);
setMinIdle(conf.minIdle);
setMaxActive(conf.maxActive);
setMaxWait(conf.maxWait);
setWhenExhaustedAction(conf.whenExhaustedAction);
setTestOnBorrow(conf.testOnBorrow);
setTestOnReturn(conf.testOnReturn);
setTestWhileIdle(conf.testWhileIdle);
setNumTestsPerEvictionRun(conf.numTestsPerEvictionRun);
setMinEvictableIdleTimeMillis(conf.minEvictableIdleTimeMillis);
setTimeBetweenEvictionRunsMillis(conf.timeBetweenEvictionRunsMillis);
setSoftMinEvictableIdleTimeMillis(conf.softMinEvictableIdleTimeMillis);
setLifo(conf.lifo);
}
allocate();
}
//-- ObjectPool methods ------------------------------------------
/**
* Borrows an object from the pool.
*
* If there is an idle instance available in the pool, then either the most-recently returned
* (if {@link #getLifo() lifo} == true) or "oldest" (lifo == false) instance sitting idle in the pool
* will be activated and returned. If activation fails, or {@link #getTestOnBorrow() 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 {@link #getMaxActive() maxActive}
* and (if applicable) {@link #getWhenExhaustedAction() whenExhaustedAction} and {@link #getMaxWait() maxWait}
* properties. If the number of instances checked out from the pool is less than maxActive,
a new
* instance is created, activated and (if applicable) validated and returned to the caller.
*
* If the pool is exhausted (no available idle instances and no capacity to create new ones),
* this method will either block ({@link #WHEN_EXHAUSTED_BLOCK}), throw a NoSuchElementException
* ({@link #WHEN_EXHAUSTED_FAIL}), or grow ({@link #WHEN_EXHAUSTED_GROW} - ignoring maxActive).
* The length of time that this method will block when whenExhaustedAction == WHEN_EXHAUSTED_BLOCK
* is determined by the {@link #getMaxWait() maxWait} property.
*
* When the pool is exhausted, multiple calling threads may be simultaneously blocked waiting for instances
* to become available. As of pool 1.5, a "fairness" algorithm has been implemented to ensure that threads receive
* available instances in request arrival order.
*
* @return object instance
* @throws NoSuchElementException if an instance cannot be returned
*/
@Override
public T borrowObject() throws Exception {
long starttime = System.currentTimeMillis();
Latch latch = new Latch();
byte whenExhaustedAction;
long maxWait;
synchronized (this) {
// Get local copy of current config. Can't sync when used later as
// it can result in a deadlock. Has the added advantage that config
// is consistent for entire method execution
whenExhaustedAction = _whenExhaustedAction;
maxWait = _maxWait;
// Add this request to the queue
_allocationQueue.add(latch);
}
// Work the allocation queue, allocating idle instances and
// instance creation permits in request arrival order
allocate();
for(;;) {
synchronized (this) {
assertOpen();
}
// If no object was allocated from the pool above
if(latch.getPair() == null) {
// check if we were allowed to create one
if(latch.mayCreate()) {
// allow new object to be created
} else {
// the pool is exhausted
switch(whenExhaustedAction) {
case WHEN_EXHAUSTED_GROW:
// allow new object to be created
synchronized (this) {
// Make sure another thread didn't allocate us an object
// or permit a new object to be created
if (latch.getPair() == null && !latch.mayCreate()) {
_allocationQueue.remove(latch);
_numInternalProcessing++;
}
}
break;
case WHEN_EXHAUSTED_FAIL:
synchronized (this) {
// Make sure allocate hasn't already assigned an object
// in a different thread or permitted a new object to be created
if (latch.getPair() != null || latch.mayCreate()) {
break;
}
_allocationQueue.remove(latch);
}
throw new NoSuchElementException("Pool exhausted");
case WHEN_EXHAUSTED_BLOCK:
try {
synchronized (latch) {
// Before we wait, make sure another thread didn't allocate us an object
// or permit a new object to be created
if (latch.getPair() == null && !latch.mayCreate()) {
if(maxWait <= 0) {
latch.wait();
} else {
// this code may be executed again after a notify then continue cycle
// so, need to calculate the amount of time to wait
final long elapsed = (System.currentTimeMillis() - starttime);
final long waitTime = maxWait - elapsed;
if (waitTime > 0)
{
latch.wait(waitTime);
}
}
} else {
break;
}
}
// see if we were awakened by a closing pool
if(isClosed() == true) {
throw new IllegalStateException("Pool closed");
}
} catch(InterruptedException e) {
boolean doAllocate = false;
synchronized(this) {
// Need to handle the all three possibilities
if (latch.getPair() == null && !latch.mayCreate()) {
// Case 1: latch still in allocation queue
// Remove latch from the allocation queue
_allocationQueue.remove(latch);
} else if (latch.getPair() == null && latch.mayCreate()) {
// Case 2: latch has been given permission to create
// a new object
_numInternalProcessing--;
doAllocate = true;
} else {
// Case 3: An object has been allocated
_numInternalProcessing--;
_numActive++;
returnObject(latch.getPair().getValue());
}
}
if (doAllocate) {
allocate();
}
Thread.currentThread().interrupt();
throw e;
}
if(maxWait > 0 && ((System.currentTimeMillis() - starttime) >= maxWait)) {
synchronized(this) {
// Make sure allocate hasn't already assigned an object
// in a different thread or permitted a new object to be created
if (latch.getPair() == null && !latch.mayCreate()) {
// Remove latch from the allocation queue
_allocationQueue.remove(latch);
} else {
break;
}
}
throw new NoSuchElementException("Timeout waiting for idle object");
} else {
continue; // keep looping
}
default:
throw new IllegalArgumentException("WhenExhaustedAction property " + whenExhaustedAction +
" not recognized.");
}
}
}
boolean newlyCreated = false;
if(null == latch.getPair()) {
try {
T obj = _factory.makeObject();
latch.setPair(new ObjectTimestampPair(obj));
newlyCreated = true;
} finally {
if (!newlyCreated) {
// object cannot be created
synchronized (this) {
_numInternalProcessing--;
// No need to reset latch - about to throw exception
}
allocate();
}
}
}
// activate & validate the object
try {
_factory.activateObject(latch.getPair().value);
if(_testOnBorrow &&
!_factory.validateObject(latch.getPair().value)) {
throw new Exception("ValidateObject failed");
}
synchronized(this) {
_numInternalProcessing--;
_numActive++;
}
return latch.getPair().value;
}
catch (Throwable e) {
PoolUtils.checkRethrow(e);
// object cannot be activated or is invalid
try {
_factory.destroyObject(latch.getPair().value);
} catch (Throwable e2) {
PoolUtils.checkRethrow(e2);
// cannot destroy broken object
}
synchronized (this) {
_numInternalProcessing--;
if (!newlyCreated) {
latch.reset();
_allocationQueue.add(0, latch);
}
}
allocate();
if(newlyCreated) {
throw new NoSuchElementException("Could not create a validated object, cause: " + e.getMessage());
}
else {
continue; // keep looping
}
}
}
}
/**
* Allocate available instances to latches in the allocation queue. Then
* set _mayCreate to true for as many additional latches remaining in queue
* as _maxActive allows. While it is safe for GOP, for consistency with GKOP
* this method should not be called from inside a sync block.
*/
private synchronized void allocate() {
if (isClosed()) return;
// First use any objects in the pool to clear the queue
for (;;) {
if (!_pool.isEmpty() && !_allocationQueue.isEmpty()) {
Latch latch = _allocationQueue.removeFirst();
latch.setPair( _pool.removeFirst());
_numInternalProcessing++;
synchronized (latch) {
latch.notify();
}
} else {
break;
}
}
// Second utilise any spare capacity to create new objects
for(;;) {
if((!_allocationQueue.isEmpty()) && (_maxActive < 0 || (_numActive + _numInternalProcessing) < _maxActive)) {
Latch latch = _allocationQueue.removeFirst();
latch.setMayCreate(true);
_numInternalProcessing++;
synchronized (latch) {
latch.notify();
}
} else {
break;
}
}
}
/**
* {@inheritDoc}
* Activation of this method decrements the active count and attempts to destroy the instance.
*
* @throws Exception if the configured {@link PoolableObjectFactory} throws an exception destroying obj
*/
@Override
public void invalidateObject(T obj) throws Exception {
try {
if (_factory != null) {
_factory.destroyObject(obj);
}
} finally {
synchronized (this) {
_numActive--;
}
allocate();
}
}
/**
* Clears any objects sitting idle in the pool by removing them from the
* idle instance pool and then invoking the configured
* {@link PoolableObjectFactory#destroyObject(Object)} 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. It locks
* the pool only during instance removal. Additional instances may be returned
* while removed items are being destroyed.
* - Exceptions encountered destroying idle instances are swallowed.
*/
@Override
public void clear() {
List> toDestroy = new ArrayList>();
synchronized(this) {
toDestroy.addAll(_pool);
_numInternalProcessing = _numInternalProcessing + _pool._size;
_pool.clear();
}
destroy(toDestroy, _factory);
}
/**
* Private method to destroy all the objects in a collection using the
* supplied object factory. Assumes that objects in the collection are
* instances of ObjectTimestampPair and that the object instances that
* they wrap were created by the factory.
*
* @param c Collection of objects to destroy
* @param factory PoolableConnectionFactory used to destroy the objects
*/
private void destroy(Collection> c, PoolableObjectFactory factory) {
for (Iterator> it = c.iterator(); it.hasNext();) {
try {
factory.destroyObject(it.next().value);
} catch(Exception e) {
// ignore error, keep destroying the rest
} finally {
synchronized(this) {
_numInternalProcessing--;
}
allocate();
}
}
}
/**
* Return the number of instances currently borrowed from this pool.
*
* @return the number of instances currently borrowed from this pool
*/
@Override
public synchronized int getNumActive() {
return _numActive;
}
/**
* Return the number of instances currently idle in this pool.
*
* @return the number of instances currently idle in this pool
*/
@Override
public synchronized int getNumIdle() {
return _pool.size();
}
/**
* Returns an object instance to the pool.
*
* 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.
*
* 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.
*
* Note: There is no guard to prevent an object
* being returned to the pool multiple times. Clients are expected to
* discard references to returned objects and ensure that an object is not
* returned to the pool multiple times in sequence (i.e., without being
* borrowed again between returns). Violating this contract will result in
* the same object appearing multiple times in the pool and pool counters
* (numActive, numIdle) returning incorrect values.
*
* @param obj instance to return to the pool
*/
@Override
public void returnObject(T obj) throws Exception {
try {
addObjectToPool(obj, true);
} catch (Exception e) {
if (_factory != null) {
try {
_factory.destroyObject(obj);
} catch (Exception e2) {
// swallowed
}
// TODO: Correctness here depends on control in addObjectToPool.
// These two methods should be refactored, removing the
// "behavior flag", decrementNumActive, from addObjectToPool.
synchronized(this) {
_numActive--;
}
allocate();
}
}
}
/**
* Adds an object to the pool.
*
* Validates the object if testOnReturn == true and passivates it before returning it to the pool.
* if validation or passivation fails, or maxIdle is set and there is no room in the pool, the instance
* is destroyed.
*
* Calls {@link #allocate()} on successful completion
*
* @param obj instance to add to the pool
* @param decrementNumActive whether or not to decrement the active count
* @throws Exception
*/
private void addObjectToPool(T obj, boolean decrementNumActive) throws Exception {
boolean success = true;
if(_testOnReturn && !(_factory.validateObject(obj))) {
success = false;
} else {
_factory.passivateObject(obj);
}
boolean shouldDestroy = !success;
// Add instance to pool if there is room and it has passed validation
// (if testOnreturn is set)
boolean doAllocate = false;
synchronized (this) {
if (isClosed()) {
shouldDestroy = true;
} else {
if((_maxIdle >= 0) && (_pool.size() >= _maxIdle)) {
shouldDestroy = true;
} else if(success) {
// borrowObject always takes the first element from the queue,
// so for LIFO, push on top, FIFO add to end
if (_lifo) {
_pool.addFirst(new ObjectTimestampPair(obj));
} else {
_pool.addLast(new ObjectTimestampPair(obj));
}
if (decrementNumActive) {
_numActive--;
}
doAllocate = true;
}
}
}
if (doAllocate) {
allocate();
}
// Destroy the instance if necessary
if(shouldDestroy) {
try {
_factory.destroyObject(obj);
} catch(Exception e) {
// ignored
}
// Decrement active count *after* destroy if applicable
if (decrementNumActive) {
synchronized(this) {
_numActive--;
}
allocate();
}
}
}
/**
* 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.
*
* Destroys idle instances in the pool by invoking {@link #clear()}.
*
* @throws Exception
*/
@Override
public void close() throws Exception {
super.close();
synchronized (this) {
clear();
startEvictor(-1L);
while(_allocationQueue.size() > 0) {
Latch l = _allocationQueue.removeFirst();
synchronized (l) {
// notify the waiting thread
l.notify();
}
}
}
}
/**
* Sets the {@link PoolableObjectFactory factory} this pool uses
* to create new instances. Trying to change
* the factory
while there are borrowed objects will
* throw an {@link IllegalStateException}. If there are instances idle
* in the pool when this method is invoked, these will be destroyed
* using the original factory.
*
* @param factory the {@link PoolableObjectFactory} used to create new instances.
* @throws IllegalStateException when the factory cannot be set at this time
* @deprecated to be removed in version 2.0
*/
@Deprecated
@Override
public void setFactory(PoolableObjectFactory factory) throws IllegalStateException {
List> toDestroy = new ArrayList>();
final PoolableObjectFactory oldFactory = _factory;
synchronized (this) {
assertOpen();
if(0 < getNumActive()) {
throw new IllegalStateException("Objects are already active");
} else {
toDestroy.addAll(_pool);
_numInternalProcessing = _numInternalProcessing + _pool._size;
_pool.clear();
}
_factory = factory;
}
destroy(toDestroy, oldFactory);
}
/**
* Perform numTests
idle object eviction tests, evicting
* examined objects that meet the criteria for eviction. If
* testWhileIdle
is true, examined objects are validated
* when visited (and removed if invalid); otherwise only objects that
* have been idle for more than minEvicableIdletimeMillis
* are removed.
*
* Successive activations of this method examine objects in
* in sequence, cycling through objects in oldest-to-youngest order.
*
* @throws Exception if the pool is closed or eviction fails.
*/
public void evict() throws Exception {
assertOpen();
synchronized (this) {
if(_pool.isEmpty()) {
return;
}
if (null == _evictionCursor) {
_evictionCursor = _pool.cursor(_lifo ? _pool.size() : 0);
}
}
for (int i=0,m=getNumTests();i pair;
synchronized (this) {
if ((_lifo && !_evictionCursor.hasPrevious()) ||
!_lifo && !_evictionCursor.hasNext()) {
_evictionCursor.close();
_evictionCursor = _pool.cursor(_lifo ? _pool.size() : 0);
}
pair = _lifo ?
_evictionCursor.previous() :
_evictionCursor.next();
_evictionCursor.remove();
_numInternalProcessing++;
}
boolean removeObject = false;
final long idleTimeMilis = System.currentTimeMillis() - pair.tstamp;
if ((getMinEvictableIdleTimeMillis() > 0) &&
(idleTimeMilis > getMinEvictableIdleTimeMillis())) {
removeObject = true;
} else if ((getSoftMinEvictableIdleTimeMillis() > 0) &&
(idleTimeMilis > getSoftMinEvictableIdleTimeMillis()) &&
((getNumIdle() + 1)> getMinIdle())) { // +1 accounts for object we are processing
removeObject = true;
}
if(getTestWhileIdle() && !removeObject) {
boolean active = false;
try {
_factory.activateObject(pair.value);
active = true;
} catch(Exception e) {
removeObject=true;
}
if(active) {
if(!_factory.validateObject(pair.value)) {
removeObject=true;
} else {
try {
_factory.passivateObject(pair.value);
} catch(Exception e) {
removeObject=true;
}
}
}
}
if (removeObject) {
try {
_factory.destroyObject(pair.value);
} catch(Exception e) {
// ignored
}
}
synchronized (this) {
if(!removeObject) {
_evictionCursor.add(pair);
if (_lifo) {
// Skip over the element we just added back
_evictionCursor.previous();
}
}
_numInternalProcessing--;
}
}
allocate();
}
/**
* Check to see if we are below our minimum number of objects
* if so enough to bring us back to our minimum.
*
* @throws Exception when {@link #addObject()} fails.
*/
private void ensureMinIdle() throws Exception {
// this method isn't synchronized so the
// calculateDeficit is done at the beginning
// as a loop limit and a second time inside the loop
// to stop when another thread already returned the
// needed objects
int objectDeficit = calculateDeficit(false);
for ( int j = 0 ; j < objectDeficit && calculateDeficit(true) > 0 ; j++ ) {
try {
addObject();
} finally {
synchronized (this) {
_numInternalProcessing--;
}
allocate();
}
}
}
/**
* This returns the number of objects to create during the pool
* sustain cycle. This will ensure that the minimum number of idle
* instances is maintained without going past the maxActive value.
*
* @param incrementInternal - Should the count of objects currently under
* some form of internal processing be
* incremented?
* @return The number of objects to be created
*/
private synchronized int calculateDeficit(boolean incrementInternal) {
int objectDeficit = getMinIdle() - getNumIdle();
if (_maxActive > 0) {
int growLimit = Math.max(0,
getMaxActive() - getNumActive() - getNumIdle() - _numInternalProcessing);
objectDeficit = Math.min(objectDeficit, growLimit);
}
if (incrementInternal && objectDeficit >0) {
_numInternalProcessing++;
}
return objectDeficit;
}
/**
* Create an object, and place it into the pool.
* addObject() is useful for "pre-loading" a pool with idle objects.
*/
@Override
public void addObject() throws Exception {
assertOpen();
if (_factory == null) {
throw new IllegalStateException("Cannot add objects without a factory.");
}
T obj = _factory.makeObject();
try {
assertOpen();
addObjectToPool(obj, false);
} catch (IllegalStateException ex) { // Pool closed
try {
_factory.destroyObject(obj);
} catch (Exception ex2) {
// swallow
}
throw ex;
}
}
//--- non-public methods ----------------------------------------
/**
* Start the eviction thread or service, or when
* delay is non-positive, stop it
* if it is already running.
*
* @param delay milliseconds between evictor runs.
*/
protected synchronized void startEvictor(long delay) {
if(null != _evictor) {
EvictionTimer.cancel(_evictor);
_evictor = null;
}
if(delay > 0) {
_evictor = new Evictor();
EvictionTimer.schedule(_evictor, delay, delay);
}
}
/**
* Returns pool info including {@link #getNumActive()}, {@link #getNumIdle()}
* and a list of objects idle in the pool with their idle times.
*
* @return string containing debug information
*/
synchronized String debugInfo() {
StringBuffer buf = new StringBuffer();
buf.append("Active: ").append(getNumActive()).append("\n");
buf.append("Idle: ").append(getNumIdle()).append("\n");
buf.append("Idle Objects:\n");
Iterator> it = _pool.iterator();
long time = System.currentTimeMillis();
while(it.hasNext()) {
ObjectTimestampPair pair = it.next();
buf.append("\t").append(pair.value).append("\t").append(time - pair.tstamp).append("\n");
}
return buf.toString();
}
/**
* Returns the number of tests to be performed in an Evictor run,
* based on the current value of numTestsPerEvictionRun
* and the number of idle instances in the pool.
*
* @see #setNumTestsPerEvictionRun
* @return the number of tests for the Evictor to run
*/
private int getNumTests() {
if(_numTestsPerEvictionRun >= 0) {
return Math.min(_numTestsPerEvictionRun, _pool.size());
} else {
return(int)(Math.ceil(_pool.size()/Math.abs((double)_numTestsPerEvictionRun)));
}
}
//--- inner classes ----------------------------------------------
/**
* The idle object evictor {@link TimerTask}.
* @see GenericObjectPool#setTimeBetweenEvictionRunsMillis
*/
private class Evictor extends TimerTask {
/**
* Run pool maintenance. Evict objects qualifying for eviction and then
* invoke {@link GenericObjectPool#ensureMinIdle()}.
*/
@Override
public void run() {
try {
evict();
} catch(Exception e) {
// ignored
} catch(OutOfMemoryError oome) {
// Log problem but give evictor thread a chance to continue in
// case error is recoverable
oome.printStackTrace(System.err);
}
try {
ensureMinIdle();
} catch(Exception e) {
// ignored
}
}
}
/**
* A simple "struct" encapsulating the
* configuration information for a {@link GenericObjectPool}.
* @see GenericObjectPool#GenericObjectPool(org.apache.commons.pool.PoolableObjectFactory,
* org.apache.commons.pool.impl.GenericObjectPool.Config)
* @see GenericObjectPool#setConfig
*/
public static class Config {
//CHECKSTYLE: stop VisibilityModifier
/**
* @see GenericObjectPool#setMaxIdle
*/
public int maxIdle = GenericObjectPool.DEFAULT_MAX_IDLE;
/**
* @see GenericObjectPool#setMinIdle
*/
public int minIdle = GenericObjectPool.DEFAULT_MIN_IDLE;
/**
* @see GenericObjectPool#setMaxActive
*/
public int maxActive = GenericObjectPool.DEFAULT_MAX_ACTIVE;
/**
* @see GenericObjectPool#setMaxWait
*/
public long maxWait = GenericObjectPool.DEFAULT_MAX_WAIT;
/**
* @see GenericObjectPool#setWhenExhaustedAction
*/
public byte whenExhaustedAction = GenericObjectPool.DEFAULT_WHEN_EXHAUSTED_ACTION;
/**
* @see GenericObjectPool#setTestOnBorrow
*/
public boolean testOnBorrow = GenericObjectPool.DEFAULT_TEST_ON_BORROW;
/**
* @see GenericObjectPool#setTestOnReturn
*/
public boolean testOnReturn = GenericObjectPool.DEFAULT_TEST_ON_RETURN;
/**
* @see GenericObjectPool#setTestWhileIdle
*/
public boolean testWhileIdle = GenericObjectPool.DEFAULT_TEST_WHILE_IDLE;
/**
* @see GenericObjectPool#setTimeBetweenEvictionRunsMillis
*/
public long timeBetweenEvictionRunsMillis = GenericObjectPool.DEFAULT_TIME_BETWEEN_EVICTION_RUNS_MILLIS;
/**
* @see GenericObjectPool#setNumTestsPerEvictionRun
*/
public int numTestsPerEvictionRun = GenericObjectPool.DEFAULT_NUM_TESTS_PER_EVICTION_RUN;
/**
* @see GenericObjectPool#setMinEvictableIdleTimeMillis
*/
public long minEvictableIdleTimeMillis = GenericObjectPool.DEFAULT_MIN_EVICTABLE_IDLE_TIME_MILLIS;
/**
* @see GenericObjectPool#setSoftMinEvictableIdleTimeMillis
*/
public long softMinEvictableIdleTimeMillis = GenericObjectPool.DEFAULT_SOFT_MIN_EVICTABLE_IDLE_TIME_MILLIS;
/**
* @see GenericObjectPool#setLifo
*/
public boolean lifo = GenericObjectPool.DEFAULT_LIFO;
//CHECKSTYLE: resume VisibilityModifier
}
/**
* Latch used to control allocation order of objects to threads to ensure
* fairness. That is, objects are allocated to threads in the order that
* threads request objects.
*/
private static final class Latch {
/** object timestamp pair allocated to this latch */
private ObjectTimestampPair _pair;
/** Whether or not this latch may create an object instance */
private boolean _mayCreate = false;
/**
* Returns ObjectTimestampPair allocated to this latch
* @return ObjectTimestampPair allocated to this latch
*/
private synchronized ObjectTimestampPair getPair() {
return _pair;
}
/**
* Sets ObjectTimestampPair on this latch
* @param pair ObjectTimestampPair allocated to this latch
*/
private synchronized void setPair(ObjectTimestampPair pair) {
_pair = pair;
}
/**
* Whether or not this latch may create an object instance
* @return true if this latch has an instance creation permit
*/
private synchronized boolean mayCreate() {
return _mayCreate;
}
/**
* Sets the mayCreate property
* @param mayCreate new value for mayCreate
*/
private synchronized void setMayCreate(boolean mayCreate) {
_mayCreate = mayCreate;
}
/**
* Reset the latch data. Used when an allocation fails and the latch
* needs to be re-added to the queue.
*/
private synchronized void reset() {
_pair = null;
_mayCreate = false;
}
}
//--- private attributes ---------------------------------------
/**
* The cap on the number of idle instances in the pool.
* @see #setMaxIdle
* @see #getMaxIdle
*/
private int _maxIdle = DEFAULT_MAX_IDLE;
/**
* The cap on the minimum number of idle instances in the pool.
* @see #setMinIdle
* @see #getMinIdle
*/
private int _minIdle = DEFAULT_MIN_IDLE;
/**
* The cap on the total number of active instances from the pool.
* @see #setMaxActive
* @see #getMaxActive
*/
private int _maxActive = DEFAULT_MAX_ACTIVE;
/**
* The maximum amount of time (in millis) the
* {@link #borrowObject} method should block before throwing
* an exception when the pool is exhausted and the
* {@link #getWhenExhaustedAction "when exhausted" action} is
* {@link #WHEN_EXHAUSTED_BLOCK}.
*
* When less than or equal to 0, the {@link #borrowObject} method
* may block indefinitely.
*
* @see #setMaxWait
* @see #getMaxWait
* @see #WHEN_EXHAUSTED_BLOCK
* @see #setWhenExhaustedAction
* @see #getWhenExhaustedAction
*/
private long _maxWait = DEFAULT_MAX_WAIT;
/**
* The action to take when the {@link #borrowObject} method
* is invoked when the pool is exhausted (the maximum number
* of "active" objects has been reached).
*
* @see #WHEN_EXHAUSTED_BLOCK
* @see #WHEN_EXHAUSTED_FAIL
* @see #WHEN_EXHAUSTED_GROW
* @see #DEFAULT_WHEN_EXHAUSTED_ACTION
* @see #setWhenExhaustedAction
* @see #getWhenExhaustedAction
*/
private byte _whenExhaustedAction = DEFAULT_WHEN_EXHAUSTED_ACTION;
/**
* When true, objects will be
* {@link PoolableObjectFactory#validateObject validated}
* before being returned by the {@link #borrowObject}
* method. If the object fails to validate,
* it will be dropped from the pool, and we will attempt
* to borrow another.
*
* @see #setTestOnBorrow
* @see #getTestOnBorrow
*/
private volatile boolean _testOnBorrow = DEFAULT_TEST_ON_BORROW;
/**
* When true, objects will be
* {@link PoolableObjectFactory#validateObject validated}
* before being returned to the pool within the
* {@link #returnObject}.
*
* @see #getTestOnReturn
* @see #setTestOnReturn
*/
private volatile boolean _testOnReturn = DEFAULT_TEST_ON_RETURN;
/**
* When true, objects will be
* {@link PoolableObjectFactory#validateObject validated}
* by the idle object evictor (if any). If an object
* fails to validate, it will be dropped from the pool.
*
* @see #setTestWhileIdle
* @see #getTestWhileIdle
* @see #getTimeBetweenEvictionRunsMillis
* @see #setTimeBetweenEvictionRunsMillis
*/
private boolean _testWhileIdle = DEFAULT_TEST_WHILE_IDLE;
/**
* The number of milliseconds to sleep between runs of the
* idle object evictor thread.
* When non-positive, no idle object evictor thread will be
* run.
*
* @see #setTimeBetweenEvictionRunsMillis
* @see #getTimeBetweenEvictionRunsMillis
*/
private long _timeBetweenEvictionRunsMillis = DEFAULT_TIME_BETWEEN_EVICTION_RUNS_MILLIS;
/**
* The max number of objects to examine during each run of the
* idle object evictor thread (if any).
*
* When a negative value is supplied, ceil({@link #getNumIdle})/abs({@link #getNumTestsPerEvictionRun})
* tests will be run. I.e., when the value is -n, roughly one nth of the
* idle objects will be tested per run.
*
* @see #setNumTestsPerEvictionRun
* @see #getNumTestsPerEvictionRun
* @see #getTimeBetweenEvictionRunsMillis
* @see #setTimeBetweenEvictionRunsMillis
*/
private int _numTestsPerEvictionRun = DEFAULT_NUM_TESTS_PER_EVICTION_RUN;
/**
* The minimum amount of time an object may sit idle in the pool
* before it is eligible for eviction by the idle object evictor
* (if any).
* When non-positive, no objects will be evicted from the pool
* due to idle time alone.
*
* @see #setMinEvictableIdleTimeMillis
* @see #getMinEvictableIdleTimeMillis
* @see #getTimeBetweenEvictionRunsMillis
* @see #setTimeBetweenEvictionRunsMillis
*/
private long _minEvictableIdleTimeMillis = DEFAULT_MIN_EVICTABLE_IDLE_TIME_MILLIS;
/**
* The minimum amount of time an object may sit idle in the pool
* before it is eligible for eviction by the idle object evictor
* (if any), with the extra condition that at least
* "minIdle" amount of object remain in the pool.
* When non-positive, no objects will be evicted from the pool
* due to idle time alone.
*
* @see #setSoftMinEvictableIdleTimeMillis
* @see #getSoftMinEvictableIdleTimeMillis
*/
private long _softMinEvictableIdleTimeMillis = DEFAULT_SOFT_MIN_EVICTABLE_IDLE_TIME_MILLIS;
/** Whether or not the pool behaves as a LIFO queue (last in first out) */
private boolean _lifo = DEFAULT_LIFO;
/** My pool. */
private CursorableLinkedList> _pool = null;
/** Eviction cursor - keeps track of idle object evictor position */
private CursorableLinkedList>.Cursor _evictionCursor = null;
/** My {@link PoolableObjectFactory}. */
private PoolableObjectFactory _factory = null;
/**
* The number of objects {@link #borrowObject} borrowed
* from the pool, but not yet returned.
*/
private int _numActive = 0;
/**
* My idle object eviction {@link TimerTask}, if any.
*/
private Evictor _evictor = null;
/**
* The number of objects subject to some form of internal processing
* (usually creation or destruction) that should be included in the total
* number of objects but are neither active nor idle.
*/
private int _numInternalProcessing = 0;
/**
* Used to track the order in which threads call {@link #borrowObject()} so
* that objects can be allocated in the order in which the threads requested
* them.
*/
private final LinkedList> _allocationQueue = new LinkedList>();
}