apache commons pool之GenericObjectPool分析(通用对象池技术)

         在高并发的环境下写程序时通常碰到线程安全的问题,当然,最能想到的就是加锁,再进一步想就是池子了,所谓池子就是,里面可以放置多个同样的对象,每个线程需要用时,就从池中取走,用完时再放回到池中,即可解决线程的安全问题,又可提高速度(预先初始化)。


       当然若是自己写个对象池的话,也是可以的,不过现在有个通用的apache下的commons-pool框架,个人感觉真是不错,尤其是现在我们用到的java框架里面,为我们省去了不少的开发成本。

     官方网址:http://commons.apache.org/proper/commons-pool/


    本文,我先只讲下通用的GenericObjectPool的原理及使用技巧。


1、主要组成类

1.1PooledObject(可被池化的对象)

默认实现DefaultPooledObject,里面封装了一个真正的用户需要池化的对象object。



其中DefaultPooledObject里面有两个方法,感觉非常秒

1、Exception borrowedBy :用于记录上次调用borrow时的堆栈,用于跟踪代码调用情况。

 @Override
    public synchronized boolean allocate() {
        if (state == PooledObjectState.IDLE) {
            state = PooledObjectState.ALLOCATED;
            lastBorrowTime = System.currentTimeMillis();
            lastUseTime = lastBorrowTime;
            borrowedCount++;
            <strong><span style="color:#ff6666;">if (logAbandoned) {
                borrowedBy = new AbandonedObjectCreatedException();
            }</span></strong>
            return true;
        } else if (state == PooledObjectState.EVICTION) {
            // TODO Allocate anyway and ignore eviction test
            state = PooledObjectState.EVICTION_RETURN_TO_HEAD;
            return false;
        }
        // TODO if validating and testOnBorrow == true then pre-allocate for
        // performance
        return false;
    }


2、Exception usedBy: 同上,记录use时的堆栈

  @Override
    public void use() {
        lastUseTime = System.currentTimeMillis();
        usedBy = new Exception("The last code to use this object was:");
    }

1.2、PooledObjectState

对象的状态,也即生命周期


allocated:即为此对象被客户端使用中

idle:在池中,处于空闲状态

eviction:在实例化GenericObjectPool对象时,内部会启动一个EvictionTimer线程线程,定期(timeBetweenEvictionRunsMillis)执行evict方法,以EvictionPolicy策略destory 状态处于idle过长的对象或idle数太多的时候。

abandoned:当池中的对象被客户端拿出后,若长时间(removeAbandonedTimeout)未返回池中,或没有调用use方法,即被标记为抛弃的,当执行removeAbandoned方法时从池中destory,并若logAbandoned为true的话,则打印调用堆栈



1.3 PooledObjectFactory(对象创建工厂)


一般需要程序员继承BasePooledObjectFactory,创建需要池化的对象,如

protected class NaviPoolableObjectFactory extends BasePooledObjectFactory<INaviDriver> {

		private Class<?> handleClass;
		private String auth;
		private ServerUrl server;

		public NaviPoolableObjectFactory(Class<?> handleClass,
				ServerUrl server, String auth) {
			this.handleClass = handleClass;
			this.auth = auth;
			this.server = server;
		}

		@Override
		public INaviDriver create() throws Exception {
			return (INaviDriver)BeanUtils.instantiateClass(handleClass
					.getDeclaredConstructor(ServerUrl.class, String.class,
							NaviPoolConfig.class), this.server, this.auth,
					poolConfig);
		}

		@Override
		public void destroyObject(PooledObject<INaviDriver> p) throws Exception {
			p.getObject().destroy();
		}

		@Override
		public boolean validateObject(PooledObject<INaviDriver> p) {
			try{
				return p.getObject().isAlive();
			}catch(Exception e){
				return false;
			}
		}

		@Override
		public PooledObject<INaviDriver> wrap(INaviDriver obj) {
			return new DefaultPooledObject<INaviDriver>(obj);
		}
	}


1.4GenericObjectPoolConfig(对象池配置)


实例化GenericObjectPool需要的配置bean

lifo:后进先出,或者先进先出

maxWaitMillis:从idle队列里面取对象时,若阻塞的话,则最大等待时长

minEvictableIdleTimeMillis:处于idle状态超过此值时,会被destory

softMinEvictableIdleTimeMillis:处于idle状态超过此值,且处于idle状态个数大于minIdle时会被destory ,正常情况下softMinEvictableIdleTimeMillis < minEvictableIdleTimeMillis

numTestsPerEvictionRun: evict线程每次遍历时evict的个数

testOnCreate:当create对象时,是否测试池化的对象是否存活

testOnBorrow: 同上,从池中borrow出来时测试

testOnReturn:同上,归还池中时测试

testWhileIdle:同上,idle状态时测试

timeBetweenEvictionRunsMillis:evict线程每次间隔时间

blockWhenExhausted:从池中取对象时,若池子用尽的话,是否阻塞等待一会maxWaitMillis

jmxEnabled:jmx是否开启监控


1.5AbandonedConfig(防止对象泄露)


abandoned:被抛弃的,即被池抛弃的设置(客户端从池里面取出去后,若长时间不归还池中,则抛弃并destory)并通过配置可以设置是否logAbandoned,若true的话,则把抛弃对象时,打印相关的日志(调用日志)


1.6ObjectPool(对象池)


对象池接口,客户端引用


1.7GenericObjectPool(通用对象池实现)


GenericObjectPool 继承BaseGenericObjectPool,并实现了ObjectPool、GenericObjectPoolMXBean、UsageTracking接口

 public GenericObjectPool(PooledObjectFactory<T> factory,
            GenericObjectPoolConfig config) {

        super(config, ONAME_BASE, config.getJmxNamePrefix());

        if (factory == null) {
            jmxUnregister(); // tidy up
            throw new IllegalArgumentException("factory may not be null");
        }
        this.factory = factory;

        setConfig(config);

        startEvictor(getTimeBetweenEvictionRunsMillis());
    }

2、主要流程

2.1 evict线程流程


虚线箭头表示方法内部调用。


2.2 完整类图




  • 3
    点赞
  • 15
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

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

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

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

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

余额充值