0
点赞
收藏
分享

微信扫一扫

java对象池commons-pool-1.6详解(二)

​​上篇文章​​ 我们详细介绍了commons-pool-1.6 java对象池的原理和基本概念,本文详细介绍不带key的对象池(ObjectPool)具体使用。

一、重点接口介绍

在Apache-commons-pool-1.6中,对不带key的对象池定义了三个顶级接口:ObjectPool、ObjectPoolFactory、PoolableObjectFactory;其中ObjectPool和ObjectPoolFactory在功能上是一样的(都有三个不同的实现类),不同点仅在于使用上不同(后者通过工厂的方式使用),具体实例见后面。PoolableObjectFactory是池化对象接口,被池化的对象需要实现该接口。

1)对象池接口:

ObjectPool接口用于管理要被池化对象的借出(borrowObject)、归还(returnObject)、失效移除(invalidateObject)、预加载(addObject)以及对象池的清空(clear、close)等,它通过PoolableObjectFactory来完成相应对象的各种操作。ObjectPoolFactory接口是对ObjectPool接口的工厂化封装,用于生产ObjectPool接口。

2)池化对象接口:

PoolableObjectFactory用于管理被池化对象(被池化的对象需要实现该接口),主要功能包括对象的产生(makeObject),激活(activateObject),挂起(passivateObject),检验(validateObject)和销毁(destroyObject)

二、对象池使用流程

1)使用者通过对象池(ObjectPool/ObjectPoolFactory)接口实现类中的borrowObject方法来从对象池中获取对象,并将active标记+1;

  1. 如果池中有idle的对象(idle>0),直接返回该对象,并将idle-1;
  2. 如果池中没有idle的对象,调用池化对象接口实现类中的makeObject方法创建对象;如果目前对象池的active数达到maxactive,那么阻塞等待;
  3. 如果配置了testonborrow=ture,那么在获取对象之前还会调用池化对象接口PoolableObjectFactory的实现类中validateObject方法来检验对象的有效性,如果非法则直接调用PoolableObjectFactory接口的实现类中destroyObject方法销毁;

2)使用完对象必须要归还给对象池,通过对象池(ObjectPool/ObjectPoolFactory)接口的实现类中的returnObject方法将对象归还到对象池中,并将active标记-1;

  1. 如果配置了testonreturn=ture,那么在归还对象前还会调用池化对象接口PoolableObjectFactory的实现类中validateObject方法来检验对象的有效性,如果非法则直接调用PoolableObjectFactory接口的实现类中destroyObject方法销毁;
  2. 如果idle数大于maxidle,则销毁对象,否则唤醒上面阻塞的进程或者放到idle区(idle+1);
  3. 如果配置了removeAbandonedTimeout,则超过该事件的池化对象直接进入放逐区;

3)驱逐检验:如果配置了timeBetweenEvictionRunsMillis,为了保证对象池的伸缩性(避免浪费资源)对象池会对idle状态的池化对象进行驱逐(minEvictableIdleTimeMillis控制驱逐空闲时间);

注:对象池只有在borrowObject的时候才回去真正创建对象(调用makeObject或者从池中的idle队列中获取),如果要预申请对象,需要调用吃对象接口ObjectPool的addObject方法。


java对象池commons-pool-1.6详解(二)_对象池


三、对象池实现类

ObjectPool接口下面有三个实现类:GenericObjectPool、StackObjectPool、SoftReferenceObjectPool。

1、genericObjectpool:(重点)

GenericObjectPool采用LIFO/FIF,池的默认行为是一个LIFO,这就意味着,当池中有空闲可用的对象时,调用borrowObject方法会返回最近(“后进”)的实例。如果LIFO策略在池中是false的,实例的返回按相反的顺序,-先进 - 先出。它利用一个org.apache.commons.collections.CursorableLinkedList对象来保存对象池里的对象。

1)这种对象池的特色是:

  • 可以设定最多能从池中借出多少个对象。
  • 可以设定池中最多能保存多少个对象。
  • 可以设定在池中已无对象可借的情况下,调用它的borrowObject方法时的行为,是等待、创建新的实例还是抛出异常。
  • 可以分别设定对象借出和还回时,是否进行有效性检查。
  • 可以设定是否使用一个单独的线程,对池内对象进行后台清理。

2)构造函数:

GenericObjectPool一共7个构造函数,最简单的是GenericObjectPool(PoolableObjectFactory factory),仅仅指明要用的PoolableObjectFactory实例,其它参数则采用默认值;此外可以通过GenericObjectPool(PoolableObjectFactory factory, GenericObjectPool.Config config) 构造函数来构造复杂的配置,其中GenericObjectPool.Config可以设置:

  • int maxActive
  • int maxIdle
  • long maxWait
  • long minEvictableIdleTimeMillis
  • int numTestsPerEvictionRun
  • boolean testOnBorrow
  • boolean testOnReturn
  • boolean testWhileIdle
  • long timeBetweenEvictionRunsMillis
  • byte whenExhaustedAction

2、StackObjectPool: 

StackObjectPool采用LIFO,利用一个java.util.Stack对象来保存对象池里的对象。

1)这种对象池的特色是:

  1. 可以为对象池指定一个初始的参考大小(当空间不够时会自动增长)。
  2. 在对象池已空的时候,调用它的borrowObject方法,会自动返回新创建的实例。
  3. 可以为对象池指定一个可保存的对象数目的上限。达到这个上限之后,再向池里送回的对象会被自动送去回收。

2)构造函数:

StackObjectPool一共6个构造函数,最简单的一个是StackObjectPool(),一切采用默认的设置,也不指明要用的PoolableObjectFactory实例;最复杂的一个则是StackObjectPool(PoolableObjectFactory factory, int max, int init),其中参数factory指明要与之配合使用的PoolableObjectFactory实例、参数max设定可保存对象数目的上限、参数init则指明初始的参考大小。

3、SoftReferenceObjectPool: 

SoftReferenceObjectPool采用LIFO,这种池额外功能是包装了每一个引用对象,允许GC根据内存需求清除这些对象。利用一个java.util.ArrayList对象来保存对象池里的对象。不过它并不在对象池里直接保存对象本身,而是保存它们的“软引用”(Soft Reference)。

1)这种对象池的特色是:

  1. 可以保存任意多个对象,不会有容量已满的情况发生。
  2. 在对象池已空的时候,调用它的borrowObject方法,会自动返回新创建的实例。
  3. 可以在初始化同时,在池内预先创建一定量的对象。
  4. 当内存不足的时候,池中的对象可以被Java虚拟机回收。

2)构造方法:

SoftReferenceObjectPool有3个构造方法,最简单的是SoftReferenceObjectPool(),不预先在池内创建对象,也不指明要用的PoolableObjectFactory实例;最复杂的一个则是SoftReferenceObjectPool(PoolableObjectFactory factory, int initSize)。其中:参数factory指明要与之配合使用的PoolableObjectFactory实例、参数initSize则指明初始化时在池中创建多少个对象


四、实例:

1)定义一个被池化的对象:

package cn.eud.nuc.pool.bean;

public class MyBean {
private Long id;
private String name;
private String other;

public void abc(int inxtInt) throws InterruptedException {
Thread.sleep(1000);
System.out.println(this.toString());
}

public MyBean(Long id, String name, String other) {
super();
this.id = id;
this.name = name;
this.other = other;
}
public Long getId() {
return id;
}
public void setId(Long id) {
this.id = id;
}
public String getName() {
return name;
}
public void setName(String name) {
this.name = name;
}
public String getOther() {
return other;
}
public void setOther(String other) {
this.other = other;
}

@Override
public String toString() {
return "MyBean [id=" + id + ", name=" + name + ", other=" + other + "]";
}

}

2)实现池化接口:

package cn.eud.nuc.pool.bean;

import java.util.concurrent.ThreadLocalRandom;

import org.apache.commons.pool.BasePoolableObjectFactory;

public class MyBeanPool extends BasePoolableObjectFactory<MyBean>{
private ThreadLocalRandom random = ThreadLocalRandom.current();

@Override
public MyBean makeObject() throws Exception {
System.out.println("make...");
long id = random.nextLong(10000000);
return new MyBean(id,System.currentTimeMillis()+"_test","");
}

@Override
public void destroyObject(MyBean client) throws Exception {
System.out.println("======================================================destroy...");
}


@Override
public boolean validateObject(MyBean client) {
return true;
}

}

3)测试类1:(使用

GenericObjectPool接口)

package cn.eud.nuc.pool;

import java.util.concurrent.ExecutorService;
import java.util.concurrent.Executors;
import java.util.concurrent.ThreadLocalRandom;

import org.apache.commons.pool.impl.GenericObjectPool;

import cn.eud.nuc.pool.bean.MyBean;
import cn.eud.nuc.pool.bean.MyBeanPool;

public class Test {
public static void main(String...strings) throws Exception {
MyBeanPool myBeanPool = new MyBeanPool();

GenericObjectPool.Config poolConfig = new GenericObjectPool.Config();
poolConfig.maxActive = 100;
poolConfig.maxIdle = 1;
//poolConfig.minIdle = 0;
poolConfig.minEvictableIdleTimeMillis = 1000000000;
poolConfig.timeBetweenEvictionRunsMillis = 10 * 2L;
poolConfig.testOnBorrow=false;
poolConfig.testOnReturn=true;
poolConfig.testWhileIdle=true;
poolConfig.lifo = false;
//poolConfig.maxWait = 100000000;
GenericObjectPool<MyBean> genericObjectPool = new GenericObjectPool<MyBean>(myBeanPool, poolConfig);
genericObjectPool.addObject();
genericObjectPool.addObject();
genericObjectPool.addObject();
genericObjectPool.addObject();
ExecutorService pool = Executors.newFixedThreadPool(200);
for (int i=0;i<5000;i++) {
pool.submit(new MyThread(genericObjectPool));
}
}
}

class MyThread implements Runnable {
private ThreadLocalRandom random = ThreadLocalRandom.current();

private GenericObjectPool<MyBean> genericObjectPool;

public MyThread(GenericObjectPool<MyBean> genericObjectPool) {
super();
this.genericObjectPool = genericObjectPool;
}

@Override
public void run() {
int nextInt = random.nextInt(100);
MyBean borrowObject = null;
boolean flag = true;
try {

borrowObject = genericObjectPool.borrowObject();
borrowObject.abc(nextInt);
} catch (Exception e) {
flag = false;
e.printStackTrace();
} finally {
try {
if (flag) {
genericObjectPool.returnObject(borrowObject);
} else {
genericObjectPool.invalidateObject(borrowObject);
}
} catch (Exception e) {
e.printStackTrace();
}
}
}
}



4)测试类2(使用GenericObjectPoolFactory接口)

package cn.eud.nuc.pool;

import java.util.concurrent.ExecutorService;
import java.util.concurrent.Executors;
import java.util.concurrent.ThreadLocalRandom;
import org.apache.commons.pool.ObjectPool;
import org.apache.commons.pool.impl.GenericObjectPool;
import org.apache.commons.pool.impl.GenericObjectPoolFactory;
import cn.eud.nuc.pool.bean.MyBean;
import cn.eud.nuc.pool.bean.MyBeanPool;

public class Test2 {
public static void main(String...strings) throws InterruptedException {
MyBeanPool myBeanPool = new MyBeanPool();

GenericObjectPool.Config poolConfig = new GenericObjectPool.Config();
poolConfig.maxActive = 100;
poolConfig.maxIdle = 1;
//poolConfig.minIdle = 0;
poolConfig.minEvictableIdleTimeMillis = 1000000000;
poolConfig.timeBetweenEvictionRunsMillis = 10 * 2L;
poolConfig.testOnBorrow=false;
poolConfig.testOnReturn=true;
poolConfig.testWhileIdle=true;
poolConfig.lifo = false;
//poolConfig.maxWait = 100000000;
GenericObjectPoolFactory<MyBean> genericObjectPoolFactory = new GenericObjectPoolFactory<>(myBeanPool, poolConfig);
ObjectPool<MyBean> createPool = genericObjectPoolFactory.createPool();

ExecutorService pool = Executors.newFixedThreadPool(200);
for (int i=0;i<5000;i++) {
pool.submit(new MyThread1(createPool));
}
}
}

class MyThread1 implements Runnable {
private ThreadLocalRandom random = ThreadLocalRandom.current();

private ObjectPool<MyBean> genericObjectPool;

public MyThread1(ObjectPool<MyBean> genericObjectPool) {
super();
this.genericObjectPool = genericObjectPool;
}

@Override
public void run() {
int nextInt = random.nextInt(100);
MyBean borrowObject = null;
boolean flag = true;
try {

borrowObject = genericObjectPool.borrowObject();
borrowObject.abc(nextInt);
} catch (Exception e) {
flag = false;
e.printStackTrace();
} finally {
try {
if (flag) {
genericObjectPool.returnObject(borrowObject);
} else {
genericObjectPool.invalidateObject(borrowObject);
}
} catch (Exception e) {
e.printStackTrace();
}
}
}
}


举报

相关推荐

0 条评论