使用对象池技术的优缺点以及代码实现

本文深入探讨了Java对象池技术的原理与应用,分析了对象池如何减少对象创建和回收的开销,以及在特定场景下提升性能和资源利用效率。文章详细介绍了对象池的实现方式,包括使用Apache Commons Pool库的具体代码示例,并讨论了对象池的优缺点。

摘要生成于 C知道 ,由 DeepSeek-R1 满血版支持, 前往体验 >

1 采用对象池的原因

Java对象的生命周期大致包括三个阶段:对象的创建,对象的使用,对象的清除。因此,对象的生命周期长度可用如下的表达式表示:T = T1 + T2 +T3.其中T1表示对象的创建时间,T2表示对象的使用时间,而T3则表示其清除时间。由此,我们可以看出,只有T2是真正有效的时间,而T1、T3则是对象本身的开销。下面再看看T1、T3在对象的整个生命周期中所占的比例。

我们知道,Java对象是通过构造函数来创建的,在这一过程中,该构造函数链中的所有构造函数也都会被自动调用。另外,默认情况下,调用类的构造函数时,Java会把变量初始化成确定的值:所有的对象被设置成null,整数变量(byte、short、int、long)设置成0,float和double变量设置成0.0,逻辑值设置成false.所以用new关键字来新建一个对象的时间开销是很大的,如表1所示。

表1 一些操作所耗费时间的对照表
.在这里插入图片描述
从表1可以看出,新建一个对象需要980个单位的时间,是本地赋值时间的980倍,是方法调用时间的166倍,而若新建一个数组所花费的时间就更多了。

2.通常我们如此实现一个业务对象池,实现org.apache.commons.pool2.的一些接口。
/
*

  • @author zhangshuo

*/
@Slf4j
public class ResourceLoaderFactory extends BasePooledObjectFactory {

/**
 * 单例工厂
 * 
 * @return
 */
public static ResourceLoaderFactory getInstance() {
	return ResourceFactoryHolder.resourceLoaderFactory;
}

private static class ResourceLoaderFactoryHolder {
	public final static ResourceLoaderFactory resourceLoaderFactory= new ResourceLoaderFactory();
}

private final GenericObjectPool<ResourceLoader> objectsPool;

public ResourceLoaderFactory() {
	GenericObjectPoolConfig config = new GenericObjectPoolConfig();
	config.setMaxTotal(1024);
	config.setMaxIdle(50);
	config.setMinIdle(8);
	// 当Pool中没有对象时不等待,而是直接new个新的
	config.setBlockWhenExhausted(false);
	AbandonedConfig abandonConfig = new AbandonedConfig();
	abandonConfig.setRemoveAbandonedTimeout(300);
	abandonConfig.setRemoveAbandonedOnBorrow(true);
	abandonConfig.setRemoveAbandonedOnMaintenance(true);
	objectsPool = new GenericObjectPool<ResourceLoader>(this, config, abandonConfig);
}

public ResourceLoader takeResourceLoader() throws Exception {
	try {
		return objectsPool.borrowObject();
	} catch (Exception e) {
		log.error("ResourceLoader error:{}",e);
	}
	return create();
}

@Override
public ResourceLoader create() throws Exception {
	return ResourceLoader.builder().build();
}

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

public void returnObject(ResourceLoader loader) {
	loader.reset();
	objectsPool.returnObject(loader);
}

}
3.对象池的优点
复用池中对象,消除创建对象、回收对象 所产生的内存开销、cpu开销以及(若跨网络)产生的网络开销.
常见的使用对象池有:在使用socket时(包括各种连接池)、线程等等

4.对象池的缺点:
现在Java的对象分配操作不比c语言的malloc调用慢, 对于轻中量级的对象, 分配/释放对象的开销可以忽略不计;
并发环境中, 多个线程可能(同时)需要获取池中对象, 进而需要在堆数据结构上进行同步或者因为锁竞争而产生阻塞, 这种开销要比创建销毁对象的开销高数百倍;
由于池中对象的数量有限, 势必成为一个可伸缩性瓶颈;
很难正确的设定对象池的大小, 如果太小则起不到作用, 如果过大, 则占用内存资源高,
对象池有其特定的适用场景:
受限的, 不需要可伸缩性的环境(cpu\内存等物理资源有限): cpu性能不够强劲, 内存比较紧张, 垃圾收集, 内存抖动会造成比较大的影响, 需要提高内存管理效率, 响应性比吞吐量更为重要;
数量受限的资源, 比如数据库连接;

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值