commons-pool2源码走读(四) 对象池实现GenericObjectPool

2018年05月27日 18:24:56 蓝墨49 阅读数 1787
 
版权声明:本文为博主原创文章,遵循CC 4.0 by-sa版权协议,转载请附上原文出处链接和本声明。

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来进行参数的初始化和对象工厂类的引入。

  1. public GenericObjectPool(final PooledObjectFactory<T> factory,
  2. final GenericObjectPoolConfig config) {
  3. //父类BaseGenericObjectPool构造方法
  4. super(config, ONAME_BASE, config.getJmxNamePrefix());
  5. if (factory == null) {
  6. jmxUnregister(); // tidy up
  7. throw new IllegalArgumentException("factory may not be null");
  8. }
  9. this.factory = factory;
  10. //空闲对象队列,此队列非JDK而是自行实现的一个队列
  11. idleObjects = new LinkedBlockingDeque<>(config.getFairness());
  12. //覆盖BaseGenericObjectPool里面的配置参数
  13. setConfig(config);
  14. //初始化回收线程
  15. startEvictor(getTimeBetweenEvictionRunsMillis());
  16. }
  • 1
  • 2
  • 3
  • 4
  • 5
  • 6
  • 7
  • 8
  • 9
  • 10
  • 11
  • 12
  • 13
  • 14
  • 15
  • 16
  • 17

3、相关属性

  1. // --- 可配置的属性 -------------------------------------------------
  2. //最大空闲数量
  3. private volatile int maxIdle = GenericObjectPoolConfig.DEFAULT_MAX_IDLE;
  4. //最小空闲数量
  5. private volatile int minIdle = GenericObjectPoolConfig.DEFAULT_MIN_IDLE;
  6. //对象工厂
  7. private final PooledObjectFactory<T> factory;
  8. // --- 内部属性 -------------------------------------------------
  9. //池中所有的对象,只能是<=maxActive
  10. private final Map<IdentityWrapper<T>, PooledObject<T>> allObjects =
  11. new ConcurrentHashMap<>();
  12. //已创建对象总数(不包含已销毁的)
  13. private final AtomicLong createCount = new AtomicLong(0);
  14. //调用创建方法总线程数
  15. private long makeObjectCount = 0;
  16. //makeObjectCount 增长时并发锁
  17. private final Object makeObjectCountLock = new Object();
  18. //空闲对象队列
  19. private final LinkedBlockingDeque<PooledObject<T>> idleObjects;
  20. // JMX specific attributes
  21. private static final String ONAME_BASE =
  22. "org.apache.commons.pool2:type=GenericObjectPool,name=";
  23. //泄漏对象回收配置参数
  24. 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、 对象池方法实现

  • 借用对象 
    整个流程为,检查池是否关闭 –> 是否回收泄漏对象 –> 是否阻塞创建对象 –> 创建对象 –> 分配对象 –> 激活对象 –> 校验对象 –> 更改借用信息 –> 返回对象
  1. public T borrowObject(final long borrowMaxWaitMillis) throws Exception {
  2. //判断对象池是否关闭:BaseGenericObjectPool.closed==true
  3. assertOpen();
  4. //如果回收泄漏的参数配置不为空,并且removeAbandonedOnBorrow参数配置为true
  5. //并且Idle数量<2,Active数量>总数Total-3
  6. //在借用时进行回收泄漏连接(会影响性能)
  7. final AbandonedConfig ac = this.abandonedConfig;
  8. if (ac != null && ac.getRemoveAbandonedOnBorrow() &&
  9. (getNumIdle() < 2) &&
  10. (getNumActive() > getMaxTotal() - 3) ) {
  11. //回收泄漏对象
  12. removeAbandoned(ac);
  13. }
  14. PooledObject<T> p = null;
  15. //copy blockWhenExhausted 防止其它线程更改getBlockWhenExhausted值造成并发问题
  16. //借用对象时如果没有是否阻塞直到有对象产生
  17. final boolean blockWhenExhausted = getBlockWhenExhausted();
  18. //创建成功标识
  19. boolean create;
  20. //记录当前时间,用作记录借用操作总共花费的时间
  21. final long waitTime = System.currentTimeMillis();
  22. //当对象为空时一直获取
  23. while (p == null) {
  24. create = false;
  25. //从双端队列弹出第一个队首对象,为空返回null
  26. p = idleObjects.pollFirst();
  27. //如果为空则重新创建一个对象
  28. if (p == null) {
  29. //创建对象
  30. p = create();
  31. //p==null可能对象池达到上限不能继续创建!
  32. if (p != null) {
  33. create = true;
  34. }
  35. }
  36. //如果对象p还是为空则阻塞等待
  37. if (blockWhenExhausted) {
  38. if (p == null) {
  39. if (borrowMaxWaitMillis < 0) {
  40. //没有超时时间则阻塞等待到有对象为止
  41. p = idleObjects.takeFirst();
  42. } else {
  43. //有超时时间
  44. p = idleObjects.pollFirst(borrowMaxWaitMillis,
  45. TimeUnit.MILLISECONDS);
  46. }
  47. }
  48. //达到超时时间,还未取到对象,则抛出异常
  49. if (p == null) {
  50. throw new NoSuchElementException(
  51. "Timeout waiting for idle object");
  52. }
  53. } else {
  54. //未取到对象,则抛出异常
  55. if (p == null) {
  56. throw new NoSuchElementException("Pool exhausted");
  57. }
  58. }
  59. //调用PooledObject.allocate()方法分配对象
  60. //[具体实现请看](https://blog.csdn.net/qq447995687/article/details/80413227)
  61. if (!p.allocate()) {
  62. p = null;
  63. }
  64. //分配成功
  65. if (p != null) {
  66. try {
  67. //激活对象,具体请看factory实现,对象重借出到归还整个流程经历的过程图
  68. factory.activateObject(p);
  69. } catch (final Exception e) {
  70. try {
  71. destroy(p);
  72. } catch (final Exception e1) {
  73. // Ignore - activation failure is more important
  74. }
  75. p = null;
  76. if (create) {
  77. final NoSuchElementException nsee = new NoSuchElementException(
  78. "Unable to activate object");
  79. nsee.initCause(e);
  80. throw nsee;
  81. }
  82. }
  83. //对象创建成功,是否进行测试
  84. if (p != null && (getTestOnBorrow() || create && getTestOnCreate())) {
  85. boolean validate = false;
  86. Throwable validationThrowable = null;
  87. try {
  88. //校验对象,具体请看factory实现,对象重借出到归还整个流程经历的过程图
  89. validate = factory.validateObject(p);
  90. } catch (final Throwable t) {
  91. PoolUtils.checkRethrow(t);
  92. validationThrowable = t;
  93. }
  94. //校验不通过则销毁对象
  95. if (!validate) {
  96. try {
  97. destroy(p);
  98. destroyedByBorrowValidationCount.incrementAndGet();
  99. } catch (final Exception e) {
  100. // Ignore - validation failure is more important
  101. }
  102. p = null;
  103. if (create) {
  104. final NoSuchElementException nsee = new NoSuchElementException(
  105. "Unable to validate object");
  106. nsee.initCause(validationThrowable);
  107. throw nsee;
  108. }
  109. }
  110. }
  111. }
  112. }
  113. //更新对象借用状态
  114. updateStatsBorrow(p, System.currentTimeMillis() - waitTime);
  115. return p.getObject();
  116. }
  • 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

创建对象 
当借用时,空闲对象为空,并且未达到池最大数量,则会调用该方法重新创建一个空闲对象

  1. private PooledObject<T> create() throws Exception {
  2. int localMaxTotal = getMaxTotal();
  3. // 如果最大数量为负数则设置为Integer的最大值
  4. if (localMaxTotal < 0) {
  5. localMaxTotal = Integer.MAX_VALUE;
  6. }
  7. // 是否创建成功的一个flag:
  8. // - TRUE: 调用工厂类成功创建一个对象
  9. // - FALSE: 返回空
  10. // - null: 重复创建
  11. Boolean create = null;
  12. while (create == null) {
  13. synchronized (makeObjectCountLock) {
  14. //加上本次操作,总共创建个数
  15. final long newCreateCount = createCount.incrementAndGet();
  16. if (newCreateCount > localMaxTotal) {
  17. //连接池容量已满,不能继续增长。在对最后一个对象的创建上,
  18. //加入了设计较为精妙,需细细揣摩
  19. createCount.decrementAndGet();
  20. //调用创建对象方法线程数=0
  21. if (makeObjectCount == 0) {
  22. //容量已满并且没有线程调用makeObject()方法,
  23. //表明没有任何可能性再继续创建对象,
  24. //返回并等待归还的空闲对象
  25. create = Boolean.FALSE;
  26. } else {
  27. //其它线程调用makeObject()方法在创建对象了。
  28. //如果继续创建则可能超过对象池容量,不返回false,因为其它线程也在创建,
  29. //但是是否能够创建成功是未知的,如果其它线程没能创建成功,
  30. //则此线程可能会抢夺到继续创建的权利。
  31. //释放锁,等待其它线程创建结束并唤醒该线程
  32. makeObjectCountLock.wait();
  33. }
  34. } else {
  35. // 对象池未满,从新创建一个对象
  36. makeObjectCount++;
  37. create = Boolean.TRUE;
  38. }
  39. }
  40. }
  41. //对象池容量达到上限,返回null重新等待其它线程归还对象
  42. if (!create.booleanValue()) {
  43. return null;
  44. }
  45. final PooledObject<T> p;
  46. try {
  47. //创建一个新对象
  48. p = factory.makeObject();
  49. } catch (final Exception e) {
  50. createCount.decrementAndGet();
  51. throw e;
  52. } finally {
  53. //与上面wait()方法相呼应,
  54. //如果上面抛出了异常,唤醒其它线程争夺继续创建最后一个资源的权利
  55. synchronized (makeObjectCountLock) {
  56. makeObjectCount--;
  57. makeObjectCountLock.notifyAll();
  58. }
  59. }
  60. //设置泄漏参数,并加入调用堆栈
  61. final AbandonedConfig ac = this.abandonedConfig;
  62. if (ac != null && ac.getLogAbandoned()) {
  63. p.setLogAbandoned(true);
  64. // TODO: in 3.0, this can use the method defined on PooledObject
  65. if (p instanceof DefaultPooledObject<?>) {
  66. ((DefaultPooledObject<T>) p).setRequireFullStackTrace(ac.getRequireFullStackTrace());
  67. }
  68. }
  69. //将创建总数增加,并将对象放入 allObjects
  70. createdCount.incrementAndGet();
  71. allObjects.put(new IdentityWrapper<>(p.getObject()), p);
  72. return p;
  73. }
  • 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

回收泄漏对象

  1. private void removeAbandoned(final AbandonedConfig ac) {
  2. // Generate a list of abandoned objects to remove
  3. final long now = System.currentTimeMillis();
  4. //超时时间=当前时间-配置的超时时间,如果一个对象的上次借用时间在此时间之前,
  5. //说明上次借用后经过了removeAbandonedTimeout时间限制还未被归还过即可能是泄漏的对象
  6. final long timeout =
  7. now - (ac.getRemoveAbandonedTimeout() * 1000L);
  8. //泄漏的,需要移除的对象列表
  9. final ArrayList<PooledObject<T>> remove = new ArrayList<>();
  10. final Iterator<PooledObject<T>> it = allObjects.values().iterator();
  11. //遍历池中对象依次判断是否需要移除
  12. while (it.hasNext()) {
  13. final PooledObject<T> pooledObject = it.next();
  14. synchronized (pooledObject) {
  15. //如果对象的状态为已分配ALLOCATED ,并且已经超过泄漏定义时间则添加到需要移除队列进行统一移除
  16. if (pooledObject.getState() == PooledObjectState.ALLOCATED &&
  17. pooledObject.getLastUsedTime() <= timeout) {
  18. pooledObject.markAbandoned();
  19. remove.add(pooledObject);
  20. }
  21. }
  22. }
  23. // 移除泄漏连接,如果配置了打印堆栈,则打印调用堆栈信息
  24. final Iterator<PooledObject<T>> itr = remove.iterator();
  25. while (itr.hasNext()) {
  26. final PooledObject<T> pooledObject = itr.next();
  27. if (ac.getLogAbandoned()) {
  28. pooledObject.printStackTrace(ac.getLogWriter());
  29. }
  30. try {
  31. //销毁对象
  32. invalidateObject(pooledObject.getObject());
  33. } catch (final Exception e) {
  34. e.printStackTrace();
  35. }
  36. }
  37. }
  • 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对象
  1. public void invalidateObject(final T obj) throws Exception {
  2. //从所有对象中取出该对象,如果不存在则抛出异常
  3. final PooledObject<T> p = allObjects.get(new IdentityWrapper<>(obj));
  4. if (p == null) {
  5. if (isAbandonedConfig()) {
  6. return;
  7. }
  8. throw new IllegalStateException(
  9. "Invalidated object not currently part of this pool");
  10. }
  11. //如果对象不是无效状态PooledObjectState.INVALID,则销毁此对象
  12. synchronized (p) {
  13. if (p.getState() != PooledObjectState.INVALID) {
  14. destroy(p);
  15. }
  16. }
  17. //
  18. ensureIdle(1, false);
  19. }
  • 1
  • 2
  • 3
  • 4
  • 5
  • 6
  • 7
  • 8
  • 9
  • 10
  • 11
  • 12
  • 13
  • 14
  • 15
  • 16
  • 17
  • 18
  • 19

销毁对象 
销毁对象,并从池中移除,更新对象池已创建数量和总销毁数量

  1. private void destroy(final PooledObject<T> toDestroy) throws Exception {
  2. toDestroy.invalidate();
  3. idleObjects.remove(toDestroy);
  4. allObjects.remove(new IdentityWrapper<>(toDestroy.getObject()));
  5. try {
  6. factory.destroyObject(toDestroy);
  7. } finally {
  8. destroyedCount.incrementAndGet();
  9. createCount.decrementAndGet();
  10. }
  11. }
  • 1
  • 2
  • 3
  • 4
  • 5
  • 6
  • 7
  • 8
  • 9
  • 10
  • 11

确保最小空闲数量

  1. private void ensureIdle(final int idleCount, final boolean always) throws Exception {
  2. //!idleObjects.hasTakeWaiters()如果idleObjects队列还有线程等待获取对象则由最后一个
  3. //等待者确保最小空闲数量
  4. if (idleCount < 1 || isClosed() || (!always && !idleObjects.hasTakeWaiters())) {
  5. return;
  6. }
  7. //一直创建空闲对象知道空闲对象数量>总空闲数量阈值
  8. while (idleObjects.size() < idleCount) {
  9. final PooledObject<T> p = create();
  10. if (p == null) {
  11. // Can't create objects, no reason to think another call to
  12. // create will work. Give up.
  13. break;
  14. }
  15. //根据先进先出参数,添加对象到队首或者队尾
  16. if (getLifo()) {
  17. idleObjects.addFirst(p);
  18. } else {
  19. idleObjects.addLast(p);
  20. }
  21. }
  22. //在此过程中如果连接池关闭则clear所有对象
  23. if (isClosed()) {
  24. clear();
  25. }
  26. }
  • 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
  • 归还对象

归还对象方法将适用完的对象从新放置回对象池中重复利用。其整个流程为:检查是否存在 –> 检查状态是否正确 –> 是否在归还时测试对象 –> 校验对象 –> 钝化(卸载)对象 –> 结束分配 –> 销毁/归还该对象 –> 更新连接池归还信息

  1. public void returnObject(final T obj) {
  2. final PooledObject<T> p = allObjects.get(new IdentityWrapper<>(obj));
  3. if (p == null) {
  4. //如果对象为空,并且没有配置泄漏参数则抛出异常,表明该对象不是连接池中的对象
  5. if (!isAbandonedConfig()) {
  6. throw new IllegalStateException(
  7. "Returned object not currently part of this pool");
  8. }
  9. //如果对象为空,表明该对象是abandoned并且已被销毁
  10. return;
  11. }
  12. synchronized(p) {
  13. final PooledObjectState state = p.getState();
  14. //如果被归还的对象不是已分配状态,抛出异常
  15. if (state != PooledObjectState.ALLOCATED) {
  16. throw new IllegalStateException(
  17. "Object has already been returned to this pool or is invalid");
  18. }
  19. //更改状态为returning,避免在此过程中被标记为被遗弃。
  20. p.markReturning();
  21. }
  22. final long activeTime = p.getActiveTimeMillis();
  23. //是否在归还时测试该对象
  24. if (getTestOnReturn()) {
  25. //校验对象
  26. if (!factory.validateObject(p)) {
  27. try {
  28. //校验不通过则destroy对象
  29. destroy(p);
  30. } catch (final Exception e) {
  31. swallowException(e);
  32. }
  33. try {
  34. //确保最小空闲数量
  35. ensureIdle(1, false);
  36. } catch (final Exception e) {
  37. swallowException(e);
  38. }
  39. //更新连接池归还信息BaseGenericObjectPool#returnedCount,activeTimes
  40. updateStatsReturn(activeTime);
  41. return;
  42. }
  43. }
  44. //校验通过
  45. try {
  46. //钝化(卸载)对象
  47. factory.passivateObject(p);
  48. } catch (final Exception e1) {
  49. swallowException(e1);
  50. try {
  51. destroy(p);
  52. } catch (final Exception e) {
  53. swallowException(e);
  54. }
  55. try {
  56. ensureIdle(1, false);
  57. } catch (final Exception e) {
  58. swallowException(e);
  59. }
  60. updateStatsReturn(activeTime);
  61. return;
  62. }
  63. //结束分配,如果对象为ALLOCATED或者RETURNING更改对象为空闲IDLE状态
  64. //具体看org.apache.commons.pool2.impl.DefaultPooledObject#deallocate方法
  65. if (!p.deallocate()) {
  66. throw new IllegalStateException(
  67. "Object has already been returned to this pool or is invalid");
  68. }
  69. final int maxIdleSave = getMaxIdle();
  70. //如果对象池已经关闭或者空闲数量达到上限,则销毁该对象
  71. if (isClosed() || maxIdleSave > -1 && maxIdleSave <= idleObjects.size()) {
  72. try {
  73. destroy(p);
  74. } catch (final Exception e) {
  75. swallowException(e);
  76. }
  77. } else {
  78. //否则将归还的对象添加到空闲队列,连接池的最终目的:重用一个连接
  79. if (getLifo()) {
  80. idleObjects.addFirst(p);
  81. } else {
  82. idleObjects.addLast(p);
  83. }
  84. if (isClosed()) {
  85. // Pool closed while object was being added to idle objects.
  86. // Make sure the returned object is destroyed rather than left
  87. // in the idle object pool (which would effectively be a leak)
  88. clear();
  89. }
  90. }
  91. updateStatsReturn(activeTime);
  92. }
  • 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连接池 
    依次销毁每个链接
  1. public void clear() {
  2. PooledObject<T> p = idleObjects.poll();
  3. while (p != null) {
  4. try {
  5. destroy(p);
  6. } catch (final Exception e) {
  7. swallowException(e);
  8. }
  9. p = idleObjects.poll();
  10. }
  11. }
  • 1
  • 2
  • 3
  • 4
  • 5
  • 6
  • 7
  • 8
  • 9
  • 10
  • 11
  • 12
  • 回收对象

此方法实现了org.apache.commons.pool2.impl.BaseGenericObjectPool#evict 方法,用于回收线程回收空闲对象。 
回收的整个流程为:判断池是否关闭及是否有空闲对象 –> 根据策略获得回收的条数 –> 判断对象状态开始进行回收 –> 根据回收策略EvictionPolicy判断是否能够回收 –> 如能回收则销毁对象 –> 不能回收则判断是否校验对象 –> 激活对象 –> 校验对象 –> 钝化对象 –> 结束回收更改对象状态 –> 回收泄漏连接

  1. public void evict() throws Exception {
  2. assertOpen();
  3. if (idleObjects.size() > 0) {
  4. PooledObject<T> underTest = null;
  5. final EvictionPolicy<T> evictionPolicy = getEvictionPolicy();
  6. synchronized (evictionLock) {
  7. //回收参数
  8. final EvictionConfig evictionConfig = new EvictionConfig(
  9. getMinEvictableIdleTimeMillis(),
  10. getSoftMinEvictableIdleTimeMillis(),
  11. getMinIdle());
  12. //是否在回收时测试对象
  13. final boolean testWhileIdle = getTestWhileIdle();
  14. //根据getNumTests()对部分对象进行回收测试
  15. for (int i = 0, m = getNumTests(); i < m; i++) {
  16. //evictionIterator是空闲对象的一个迭代器,可以想象为idleObjects.iterator()
  17. if (evictionIterator == null || !evictionIterator.hasNext()) {
  18. evictionIterator = new EvictionIterator(idleObjects);
  19. }
  20. if (!evictionIterator.hasNext()) {
  21. // Pool exhausted, nothing to do here
  22. return;
  23. }
  24. //多线程并发时,有可能上面检测到有对象,而另一个对象随后将其借出
  25. try {
  26. underTest = evictionIterator.next();
  27. } catch (final NoSuchElementException nsee) {
  28. // 对象被其它线程借出
  29. i--;
  30. evictionIterator = null;
  31. continue;
  32. }
  33. //根据状态判断是否能够开始回收测试,并更改状态,详细实现请看源码走读(一)
  34. if (!underTest.startEvictionTest()) {
  35. // Object was borrowed in another thread
  36. // Don't count this as an eviction test so reduce i;
  37. i--;
  38. continue;
  39. }
  40. //根据回收策略判断对象是否能够被回收,单独分析
  41. boolean evict;
  42. try {
  43. //根据回收策略判断对象是否能够被回收
  44. evict = evictionPolicy.evict(evictionConfig, underTest,
  45. idleObjects.size());
  46. } catch (final Throwable t) {
  47. // Slightly convoluted as SwallowedExceptionListener
  48. // uses Exception rather than Throwable
  49. PoolUtils.checkRethrow(t);
  50. swallowException(new Exception(t));
  51. // Don't evict on error conditions
  52. evict = false;
  53. }
  54. //如果能被回收则销毁对象
  55. if (evict) {
  56. destroy(underTest);
  57. destroyedByEvictorCount.incrementAndGet();
  58. } else {
  59. //不能被回收,则是否进行校验,与借出流程相同,只不过该处只是校验而没有借出实际使用
  60. if (testWhileIdle) {
  61. boolean active = false;
  62. try {
  63. //对象已经被借出,直接激活
  64. factory.activateObject(underTest);
  65. active = true;
  66. } catch (final Exception e) {
  67. destroy(underTest);
  68. destroyedByEvictorCount.incrementAndGet();
  69. }
  70. if (active) {
  71. //激活成功进行校验
  72. if (!factory.validateObject(underTest)) {
  73. //校验不通过则销毁对象
  74. destroy(underTest);
  75. destroyedByEvictorCount.incrementAndGet();
  76. } else {
  77. try {
  78. //校验通过则重新将对象钝化(卸载)
  79. factory.passivateObject(underTest);
  80. } catch (final Exception e) {
  81. destroy(underTest);
  82. destroyedByEvictorCount.incrementAndGet();
  83. }
  84. }
  85. }
  86. }
  87. //结束回收测试,更改对象状态或者添加到空闲队列,
  88. //如果在此途中被借出,还需重新添加到idleObjects,具体实现请看源码走读(一)
  89. if (!underTest.endEvictionTest(idleObjects)) {
  90. // TODO - May need to add code here once additional
  91. // states are used
  92. }
  93. }
  94. }
  95. }
  96. }
  97. //配置了回收,则进行回收泄漏连接
  98. final AbandonedConfig ac = this.abandonedConfig;
  99. if (ac != null && ac.getRemoveAbandonedOnMaintenance()) {
  100. removeAbandoned(ac);
  101. }
  102. }
  • 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

返回有多少对象需要进行回收测试

  1. private int getNumTests() {
  2. final int numTestsPerEvictionRun = getNumTestsPerEvictionRun();
  3. if (numTestsPerEvictionRun >= 0) {
  4. return Math.min(numTestsPerEvictionRun, idleObjects.size());
  5. }
  6. return (int) (Math.ceil(idleObjects.size() /
  7. Math.abs((double) numTestsPerEvictionRun)));
  8. }
 
  • 1
  • 2
  • 3
  • 4
  • 5
  • 6
  • 7
  • 8
 

GenericObjectPool的更多相关文章

  1. commons-pool实战之 GenericObjectPool和GenericKeyedObjectPool

    前面两篇文章说了怎么样简单的使用commons-pool库,这里需要考虑一个问题就是在很多时候我们在池里的对象都是比较重型的并且大多数比较稀缺的 资源,比如说数据库连接,这样如果一直把一些连接放在池里 ...

  2. NoClassDefFoundError: org/apache/commons/pool/impl/GenericObjectPool

    错误:Exception in thread "main" java.lang.NoClassDefFoundError: org/apache/commons/pool/impl ...

  3. Spring + Tomcat 启动报错java.lang.ClassNotFoundException: org.apache.commons.pool.impl.GenericObjectPool

    错误如下: -- ::,-[TS] INFO http-- org.springframework.beans.factory.support.DefaultListableBeanFactory - ...

  4. org/apache/commons/pool/impl/GenericObjectPool异常的解决办法

    org/apache/commons/pool/impl/GenericObjectPool异常的解决办法 webwork+spring+hibernate框架的集成, 一启动Tomcat服务器就出了 ...

  5. Lettuce连接池——解决“MXBean already registered with name org.apache.commons.pool2:type=GenericObjectPool,name=pool”

    LettuceConfig: package com.youdao.outfox.interflow.config; import io.lettuce.core.support.Connection ...

  6. 对象池技术和通用实现GenericObjectPool

    对象池技术其实蛮常见的,比如线程池.数据库连接池 他们的特点是:对象创建代价较高.比较消耗资源.比较耗时: 比如 mysql数据库连接建立就要先建立 tcp三次握手.发送用户名/密码.进行身份校验.权 ...

  7. Caused by: java.lang.ClassNotFoundException: org.apache.commons.pool.impl.GenericObjectPool

    原因:缺少commons-pool-X.jar包,到http://commons.apache.org/proper/commons-pool/download_pool.cgi下载后引入即可(地址可 ...

  8. java——通过GenericObjectPool获取到的资源,调用close()方法会close还是returnObject?

    一种优雅的关闭资源的方式是使用try(){}cache(){} 就像这样: 这时候,try()里面的资源会在return语句执行结束之后自动调用close()方法,那么问题来了,当我们使用连接池的时候 ...

  9. Netty实现高性能RPC服务器优化篇之消息序列化

    在本人写的前一篇文章中,谈及有关如何利用Netty开发实现,高性能RPC服务器的一些设计思路.设计原理,以及具体的实现方案(具体参见:谈谈如何使用Netty开发实现高性能的RPC服务器).在文章的最后 ...

随机推荐

  1. python assert 在正式产品里禁用的手法 直接-O即可

    How do I disable assertions in Python? There are multiple approaches that affect a single process, t ...

  2. Xenia and Weights(Codeforces Round #197 (Div. 2)+DP)

    题目链接 传送门 思路 \(dp[i][j][k]\)表示第\(i\)次操作放\(j\)后与另一堆的重量差为\(k\)是否存在. 代码实现如下 #include <set> #includ ...

  3. Python 爬虫js加密破解(四) 360云盘登录password加密

    登录链接:https://yunpan.360.cn/mindex/login 这是一个md5 加密算法,直接使用 md5加密即可实现 本文讲解的是如何抠出js,运行代码 第一部:抓包 如图 第二步: ...

  4. Maven之setting.xml 配置详解

    文件存放位置 全局配置: ${M2_HOME}/conf/settings.xml 用户配置: ${user.home}/.m2/settings.xml note:用户配置优先于全局配置.${use ...

  5. 使用selenium三种方式打开文件:

    #路径读取方式一:# b.get(r"C:\我的代码\selenium自动化测试\test.html")#路径读取方式二:# b.get("C:\\我的代码\\selen ...

  6. rs485一主多从的连接方式及通信注意事项

    rs485的通信方式看似比较简单,其实通信软件的处理还是有需要注意的. 下图是主机向从机发送信息的示意图,其中485的线都是手牵手相连的,因此主机向下发的时候,其实各个从机都有在接收数据的,只是,从机 ...

  7. OLED液晶屏幕(2)取模软件

    https://blog.csdn.net/ling3ye/article/details/53399305 文件夹说明: Adafruit_SSD1306-master   ——SSD1306库(O ...

  8. Time Frequency (T-F) Masking Technique

    时频掩蔽技术. 掩蔽效应 声掩蔽(auditory masking)是指一个声音的听阈因另一个声音的存在而上升的现象.纯音被白噪声所掩蔽时,纯音听阈上升的分贝数,主要决定于以纯音频率为中心一个窄带噪声 ...

  9. LeetCode 923. 3Sum With Multiplicity

    原题链接在这里:https://leetcode.com/problems/3sum-with-multiplicity/ 题目: Given an integer array A, and an i ...

  10. 将idea中xml文件背景颜色去除(转)

    原贴链接:https://blog.csdn.net/weixin_43215250/article/details/89403678 第一步:除去SQL代码块的背景颜色,步骤如下 设置后还是很影响视 ...