GenericObjectPool
commons-pool2源码走读(四) 对象池实现GenericObjectPool
commons-pool2源码走读(四) 对象池实现GenericObjectPool<T>
GenericObjectPool <T> 是一个可配置的ObjectPool实现。
当与适当的PooledObjectFactory组合使用时,GenericObjectPool为任意对象提供健壮的池功能。
您可以选择性的配置池来检查和可能回收池中的空闲对象,并确保有最少数量的空闲对象可用。这是由一个“空闲对象回收”线程(即BaseGenericObjectPool <T> 的Evictor)执行的,线程是异步运行的。在配置这个可选特性时,应该谨慎使用。驱逐运行与客户端线程争用池中的对象,因此如果它们运行得太频繁,可能会导致性能问题。
还可以配置池来检测和删除被泄漏的对象,比如一个从池中借出的对象,在超过removeAbandonedTimeout超时之前既不使用也不返回。移除泄漏的连接,可能发生在对象被借用时对象池已接近饱和,也可能是被回收线程检查出,或者两者都执行时。如果池对象实现了TrackedUse接口,那么其最后一次使用时间使取决于getLastUsed方法;否则,是由对象从池中借出的时间决定。
实现注意:为了防止可能的死锁,已经采取了谨慎措施,以确保在同步块中不会发生对工厂方法的调用。这个类线程安全。
1、接口继承、实现关系
GenericObjectPool <T> 实现了ObjectPool<T> 具备对象池的功能,同时 继承了BaseGenericObjectPool<T> 的对于对象状态管理和回收等功能。
2、构造函数
构造函数通过GenericObjectPoolConfig 和PooledObjectFactory来进行参数的初始化和对象工厂类的引入。
public GenericObjectPool(final PooledObjectFactory<T> factory,
final GenericObjectPoolConfig config) {
//父类BaseGenericObjectPool构造方法
super(config, ONAME_BASE, config.getJmxNamePrefix());
if (factory == null) {
jmxUnregister(); // tidy up
throw new IllegalArgumentException("factory may not be null");
}
this.factory = factory;
//空闲对象队列,此队列非JDK而是自行实现的一个队列
idleObjects = new LinkedBlockingDeque<>(config.getFairness());
//覆盖BaseGenericObjectPool里面的配置参数
setConfig(config);
//初始化回收线程
startEvictor(getTimeBetweenEvictionRunsMillis());
}
- 1
- 2
- 3
- 4
- 5
- 6
- 7
- 8
- 9
- 10
- 11
- 12
- 13
- 14
- 15
- 16
- 17
3、相关属性
// --- 可配置的属性 -------------------------------------------------
//最大空闲数量
private volatile int maxIdle = GenericObjectPoolConfig.DEFAULT_MAX_IDLE;
//最小空闲数量
private volatile int minIdle = GenericObjectPoolConfig.DEFAULT_MIN_IDLE;
//对象工厂
private final PooledObjectFactory<T> factory;
// --- 内部属性 -------------------------------------------------
//池中所有的对象,只能是<=maxActive
private final Map<IdentityWrapper<T>, PooledObject<T>> allObjects =
new ConcurrentHashMap<>();
//已创建对象总数(不包含已销毁的)
private final AtomicLong createCount = new AtomicLong(0);
//调用创建方法总线程数
private long makeObjectCount = 0;
//makeObjectCount 增长时并发锁
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=";
//泄漏对象回收配置参数
private volatile AbandonedConfig abandonedConfig = null;
- 1
- 2
- 3
- 4
- 5
- 6
- 7
- 8
- 9
- 10
- 11
- 12
- 13
- 14
- 15
- 16
- 17
- 18
- 19
- 20
- 21
- 22
- 23
- 24
- 25
- 26
- 27
- 28
4、 对象池方法实现
- 借用对象
整个流程为,检查池是否关闭 –> 是否回收泄漏对象 –> 是否阻塞创建对象 –> 创建对象 –> 分配对象 –> 激活对象 –> 校验对象 –> 更改借用信息 –> 返回对象
public T borrowObject(final long borrowMaxWaitMillis) throws Exception {
//判断对象池是否关闭:BaseGenericObjectPool.closed==true
assertOpen();
//如果回收泄漏的参数配置不为空,并且removeAbandonedOnBorrow参数配置为true
//并且Idle数量<2,Active数量>总数Total-3
//在借用时进行回收泄漏连接(会影响性能)
final AbandonedConfig ac = this.abandonedConfig;
if (ac != null && ac.getRemoveAbandonedOnBorrow() &&
(getNumIdle() < 2) &&
(getNumActive() > getMaxTotal() - 3) ) {
//回收泄漏对象
removeAbandoned(ac);
}
PooledObject<T> p = null;
//copy blockWhenExhausted 防止其它线程更改getBlockWhenExhausted值造成并发问题
//借用对象时如果没有是否阻塞直到有对象产生
final boolean blockWhenExhausted = getBlockWhenExhausted();
//创建成功标识
boolean create;
//记录当前时间,用作记录借用操作总共花费的时间
final long waitTime = System.currentTimeMillis();
//当对象为空时一直获取
while (p == null) {
create = false;
//从双端队列弹出第一个队首对象,为空返回null
p = idleObjects.pollFirst();
//如果为空则重新创建一个对象
if (p == null) {
//创建对象
p = create();
//p==null可能对象池达到上限不能继续创建!
if (p != null) {
create = true;
}
}
//如果对象p还是为空则阻塞等待
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");
}
}
//调用PooledObject.allocate()方法分配对象
//[具体实现请看](https://blog.csdn.net/qq447995687/article/details/80413227)
if (!p.allocate()) {
p = null;
}
//分配成功
if (p != null) {
try {
//激活对象,具体请看factory实现,对象重借出到归还整个流程经历的过程图
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() || create && getTestOnCreate())) {
boolean validate = false;
Throwable validationThrowable = null;
try {
//校验对象,具体请看factory实现,对象重借出到归还整个流程经历的过程图
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();
}
- 1
- 2
- 3
- 4
- 5
- 6
- 7
- 8
- 9
- 10
- 11
- 12
- 13
- 14
- 15
- 16
- 17
- 18
- 19
- 20
- 21
- 22
- 23
- 24
- 25
- 26
- 27
- 28
- 29
- 30
- 31
- 32
- 33
- 34
- 35
- 36
- 37
- 38
- 39
- 40
- 41
- 42
- 43
- 44
- 45
- 46
- 47
- 48
- 49
- 50
- 51
- 52
- 53
- 54
- 55
- 56
- 57
- 58
- 59
- 60
- 61
- 62
- 63
- 64
- 65
- 66
- 67
- 68
- 69
- 70
- 71
- 72
- 73
- 74
- 75
- 76
- 77
- 78
- 79
- 80
- 81
- 82
- 83
- 84
- 85
- 86
- 87
- 88
- 89
- 90
- 91
- 92
- 93
- 94
- 95
- 96
- 97
- 98
- 99
- 100
- 101
- 102
- 103
- 104
- 105
- 106
- 107
- 108
- 109
- 110
- 111
- 112
- 113
- 114
- 115
- 116
- 117
- 118
- 119
创建对象
当借用时,空闲对象为空,并且未达到池最大数量,则会调用该方法重新创建一个空闲对象
private PooledObject<T> create() throws Exception {
int localMaxTotal = getMaxTotal();
// 如果最大数量为负数则设置为Integer的最大值
if (localMaxTotal < 0) {
localMaxTotal = Integer.MAX_VALUE;
}
// 是否创建成功的一个flag:
// - TRUE: 调用工厂类成功创建一个对象
// - FALSE: 返回空
// - null: 重复创建
Boolean create = null;
while (create == null) {
synchronized (makeObjectCountLock) {
//加上本次操作,总共创建个数
final long newCreateCount = createCount.incrementAndGet();
if (newCreateCount > localMaxTotal) {
//连接池容量已满,不能继续增长。在对最后一个对象的创建上,
//加入了设计较为精妙,需细细揣摩
createCount.decrementAndGet();
//调用创建对象方法线程数=0
if (makeObjectCount == 0) {
//容量已满并且没有线程调用makeObject()方法,
//表明没有任何可能性再继续创建对象,
//返回并等待归还的空闲对象
create = Boolean.FALSE;
} else {
//其它线程调用makeObject()方法在创建对象了。
//如果继续创建则可能超过对象池容量,不返回false,因为其它线程也在创建,
//但是是否能够创建成功是未知的,如果其它线程没能创建成功,
//则此线程可能会抢夺到继续创建的权利。
//释放锁,等待其它线程创建结束并唤醒该线程
makeObjectCountLock.wait();
}
} else {
// 对象池未满,从新创建一个对象
makeObjectCount++;
create = Boolean.TRUE;
}
}
}
//对象池容量达到上限,返回null重新等待其它线程归还对象
if (!create.booleanValue()) {
return null;
}
final PooledObject<T> p;
try {
//创建一个新对象
p = factory.makeObject();
} catch (final Exception e) {
createCount.decrementAndGet();
throw e;
} finally {
//与上面wait()方法相呼应,
//如果上面抛出了异常,唤醒其它线程争夺继续创建最后一个资源的权利
synchronized (makeObjectCountLock) {
makeObjectCount--;
makeObjectCountLock.notifyAll();
}
}
//设置泄漏参数,并加入调用堆栈
final AbandonedConfig ac = this.abandonedConfig;
if (ac != null && ac.getLogAbandoned()) {
p.setLogAbandoned(true);
// TODO: in 3.0, this can use the method defined on PooledObject
if (p instanceof DefaultPooledObject<?>) {
((DefaultPooledObject<T>) p).setRequireFullStackTrace(ac.getRequireFullStackTrace());
}
}
//将创建总数增加,并将对象放入 allObjects
createdCount.incrementAndGet();
allObjects.put(new IdentityWrapper<>(p.getObject()), p);
return p;
}
- 1
- 2
- 3
- 4
- 5
- 6
- 7
- 8
- 9
- 10
- 11
- 12
- 13
- 14
- 15
- 16
- 17
- 18
- 19
- 20
- 21
- 22
- 23
- 24
- 25
- 26
- 27
- 28
- 29
- 30
- 31
- 32
- 33
- 34
- 35
- 36
- 37
- 38
- 39
- 40
- 41
- 42
- 43
- 44
- 45
- 46
- 47
- 48
- 49
- 50
- 51
- 52
- 53
- 54
- 55
- 56
- 57
- 58
- 59
- 60
- 61
- 62
- 63
- 64
- 65
- 66
- 67
- 68
- 69
- 70
- 71
- 72
- 73
- 74
- 75
回收泄漏对象
private void removeAbandoned(final AbandonedConfig ac) {
// Generate a list of abandoned objects to remove
final long now = System.currentTimeMillis();
//超时时间=当前时间-配置的超时时间,如果一个对象的上次借用时间在此时间之前,
//说明上次借用后经过了removeAbandonedTimeout时间限制还未被归还过即可能是泄漏的对象
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) {
//如果对象的状态为已分配ALLOCATED ,并且已经超过泄漏定义时间则添加到需要移除队列进行统一移除
if (pooledObject.getState() == PooledObjectState.ALLOCATED &&
pooledObject.getLastUsedTime() <= timeout) {
pooledObject.markAbandoned();
remove.add(pooledObject);
}
}
}
// 移除泄漏连接,如果配置了打印堆栈,则打印调用堆栈信息
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();
}
}
}
- 1
- 2
- 3
- 4
- 5
- 6
- 7
- 8
- 9
- 10
- 11
- 12
- 13
- 14
- 15
- 16
- 17
- 18
- 19
- 20
- 21
- 22
- 23
- 24
- 25
- 26
- 27
- 28
- 29
- 30
- 31
- 32
- 33
- 34
- 35
- 36
- 37
- 38
- invalidate对象
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");
}
//如果对象不是无效状态PooledObjectState.INVALID,则销毁此对象
synchronized (p) {
if (p.getState() != PooledObjectState.INVALID) {
destroy(p);
}
}
//
ensureIdle(1, false);
}
- 1
- 2
- 3
- 4
- 5
- 6
- 7
- 8
- 9
- 10
- 11
- 12
- 13
- 14
- 15
- 16
- 17
- 18
- 19
销毁对象
销毁对象,并从池中移除,更新对象池已创建数量和总销毁数量
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();
}
}
- 1
- 2
- 3
- 4
- 5
- 6
- 7
- 8
- 9
- 10
- 11
确保最小空闲数量
private void ensureIdle(final int idleCount, final boolean always) throws Exception {
//!idleObjects.hasTakeWaiters()如果idleObjects队列还有线程等待获取对象则由最后一个
//等待者确保最小空闲数量
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);
}
}
//在此过程中如果连接池关闭则clear所有对象
if (isClosed()) {
clear();
}
}
- 1
- 2
- 3
- 4
- 5
- 6
- 7
- 8
- 9
- 10
- 11
- 12
- 13
- 14
- 15
- 16
- 17
- 18
- 19
- 20
- 21
- 22
- 23
- 24
- 25
- 26
- 归还对象
归还对象方法将适用完的对象从新放置回对象池中重复利用。其整个流程为:检查是否存在 –> 检查状态是否正确 –> 是否在归还时测试对象 –> 校验对象 –> 钝化(卸载)对象 –> 结束分配 –> 销毁/归还该对象 –> 更新连接池归还信息
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");
}
//如果对象为空,表明该对象是abandoned并且已被销毁
return;
}
synchronized(p) {
final PooledObjectState state = p.getState();
//如果被归还的对象不是已分配状态,抛出异常
if (state != PooledObjectState.ALLOCATED) {
throw new IllegalStateException(
"Object has already been returned to this pool or is invalid");
}
//更改状态为returning,避免在此过程中被标记为被遗弃。
p.markReturning();
}
final long activeTime = p.getActiveTimeMillis();
//是否在归还时测试该对象
if (getTestOnReturn()) {
//校验对象
if (!factory.validateObject(p)) {
try {
//校验不通过则destroy对象
destroy(p);
} catch (final Exception e) {
swallowException(e);
}
try {
//确保最小空闲数量
ensureIdle(1, false);
} catch (final Exception e) {
swallowException(e);
}
//更新连接池归还信息BaseGenericObjectPool#returnedCount,activeTimes
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;
}
//结束分配,如果对象为ALLOCATED或者RETURNING更改对象为空闲IDLE状态
//具体看org.apache.commons.pool2.impl.DefaultPooledObject#deallocate方法
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);
}
- 1
- 2
- 3
- 4
- 5
- 6
- 7
- 8
- 9
- 10
- 11
- 12
- 13
- 14
- 15
- 16
- 17
- 18
- 19
- 20
- 21
- 22
- 23
- 24
- 25
- 26
- 27
- 28
- 29
- 30
- 31
- 32
- 33
- 34
- 35
- 36
- 37
- 38
- 39
- 40
- 41
- 42
- 43
- 44
- 45
- 46
- 47
- 48
- 49
- 50
- 51
- 52
- 53
- 54
- 55
- 56
- 57
- 58
- 59
- 60
- 61
- 62
- 63
- 64
- 65
- 66
- 67
- 68
- 69
- 70
- 71
- 72
- 73
- 74
- 75
- 76
- 77
- 78
- 79
- 80
- 81
- 82
- 83
- 84
- 85
- 86
- 87
- 88
- 89
- 90
- 91
- 92
- 93
- 94
- 95
- 96
- clear连接池
依次销毁每个链接
public void clear() {
PooledObject<T> p = idleObjects.poll();
while (p != null) {
try {
destroy(p);
} catch (final Exception e) {
swallowException(e);
}
p = idleObjects.poll();
}
}
- 1
- 2
- 3
- 4
- 5
- 6
- 7
- 8
- 9
- 10
- 11
- 12
- 回收对象
此方法实现了org.apache.commons.pool2.impl.BaseGenericObjectPool#evict 方法,用于回收线程回收空闲对象。
回收的整个流程为:判断池是否关闭及是否有空闲对象 –> 根据策略获得回收的条数 –> 判断对象状态开始进行回收 –> 根据回收策略EvictionPolicy判断是否能够回收 –> 如能回收则销毁对象 –> 不能回收则判断是否校验对象 –> 激活对象 –> 校验对象 –> 钝化对象 –> 结束回收更改对象状态 –> 回收泄漏连接
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();
//根据getNumTests()对部分对象进行回收测试
for (int i = 0, m = getNumTests(); i < m; i++) {
//evictionIterator是空闲对象的一个迭代器,可以想象为idleObjects.iterator()
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) {
// 对象被其它线程借出
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;
}
//根据回收策略判断对象是否能够被回收,单独分析
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();
}
}
}
}
//结束回收测试,更改对象状态或者添加到空闲队列,
//如果在此途中被借出,还需重新添加到idleObjects,具体实现请看源码走读(一)
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);
}
}
- 1
- 2
- 3
- 4
- 5
- 6
- 7
- 8
- 9
- 10
- 11
- 12
- 13
- 14
- 15
- 16
- 17
- 18
- 19
- 20
- 21
- 22
- 23
- 24
- 25
- 26
- 27
- 28
- 29
- 30
- 31
- 32
- 33
- 34
- 35
- 36
- 37
- 38
- 39
- 40
- 41
- 42
- 43
- 44
- 45
- 46
- 47
- 48
- 49
- 50
- 51
- 52
- 53
- 54
- 55
- 56
- 57
- 58
- 59
- 60
- 61
- 62
- 63
- 64
- 65
- 66
- 67
- 68
- 69
- 70
- 71
- 72
- 73
- 74
- 75
- 76
- 77
- 78
- 79
- 80
- 81
- 82
- 83
- 84
- 85
- 86
- 87
- 88
- 89
- 90
- 91
- 92
- 93
- 94
- 95
- 96
- 97
- 98
- 99
- 100
- 101
- 102
- 103
- 104
- 105
- 106
返回有多少对象需要进行回收测试
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)));
}
- 1
- 2
- 3
- 4
- 5
- 6
- 7
- 8