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方法。



三、对象池实现类

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();
			}
		}
	}
}

参考:

https://www.cnblogs.com/shipengzhi/archive/2011/06/02/2068565.html

  • 2
    点赞
  • 4
    收藏
    觉得还不错? 一键收藏
  • 打赏
    打赏
  • 0
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包

打赏作者

赶路人儿

你的鼓励将是我创作的最大动力

¥1 ¥2 ¥4 ¥6 ¥10 ¥20
扫码支付:¥1
获取中
扫码支付

您的余额不足,请更换扫码支付或充值

打赏作者

实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值