简化对象池

本文介绍了Java对象池的作用,虽Java虚拟机(JVM)在管理对象创建和销毁方面有改进,但对象池仍有益处。它能更好运用资源、降低初始化成本。还阐述了通用的Java对象池架构,包含PoolManager类等,可控制对象池容量等,能提高应用程序效率。

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

在Java中开发一个普遍性的对象池架构可以更好地利用资源,并可以使初始化的成本达到最小。
——by Karthik Rangaraju

大多数人对直接或间接运用对象池来连接一个数据库都很熟悉。但通常你也可以将对象放入对象池中从而节省重要的资源、提高程序的效率并控制对不充足资源的访问。出于对设计、成本或性能的考虑,放入对象池中的对象通常是有限的。它们或者是初始化成本很高的对象,或者是很少用的对象。运用对象池,我们就可以管理竞争性客户端对有限的对象集的访问。

Sun公司的Java HotSpot技术开发小组建议,Java程序员不要用他们自己的对象池。作为替代,它建议他们用Java虚拟机(JVM)中的改进的内存管理和对象分配。虽然HotSpot比以前的JVMs在管理对象创建和销毁方面更有效,但它不能使以JVM之外的资源为依托的对象的创建达到最优。所以,尽管HotSpot的性能有所提高,但你仍可以从对象池受益。

对象池主要是可以更好地运用你的资源。例如,设想有相当多的客户要有效地运用很少的数据库或网络连接。通过限制对对象的访问(只在客户端需要的时候才能访问对象),你就可以释放资源,让其它客户端使用。通过对象池提高对象的利用率通常可以提高系统性能。

你可以用对象池使初始化的成本达到最小。典型的例子包括数据库、网络连接和线程。这样的连接通常需要很多时间来初始化。一旦创建了这些连接,你就可以重用它们,从而极大地节省了成本。因此,你可以将初始化成本很高(从时间、内存或其它资源方面考虑)的对象放入对象池中。例如,大多数容器都将Enterprise JavaBeans放入对象池中,从而避免重复的资源分配和状态初始化。

让我们来考虑一个普遍性的可以容纳任何Java对象的对象池架构。这个架构包含一个主要的PoolManager类,它可以让我们访问对象池中的对象。通过调用PoolManager.get(),你就可以得到对象,该方法从对象池读取对象,将它封装在一个PooledResource容器对象中,并返回对该容器的引用。你可以通过调用PooledResource.release()将对象返回到对象池。为了使PoolManager可以扩展,我运用了Strategy设计模式(见Design Patterns: Elements of Reusable Object-Oriented Software一书中的描述),它可以让应用程序定义对象创建和对象池容量管理策略。ObjectManager类是实现下面这些功能的关键:应用程序必须扩展ObjectManager,提供创建逻辑将对象放入对象池中,并提供策略来加大或减小对象池的容量,而且也可以定期刷新对象池中的对象。

PoolManager为不同的对象池容量管理策略提供了构造器(见列表1)。

构建PoolManager

列表 1. PoolManager类可以让我们访问对象池中的对象,并为不同的对象池容量管理策略提供构造器。


当PoolManager是用初始的、最大的容量构建的时,它就调用ObjectManager.create()来创建一个初始的对象集。当客户端请求一个对象而它的初始集已经满了时,对象池的容量就会加大,直到达到最大。这时候,新的请求就会调用ObjectManager.increasePoolSize()。只要increasePoolSize()不被覆盖,请求就会被阻塞,直到一个对象被释放回对象池。

通过确定最大容量来构建PoolManager会导致lazy initialization,这就是说在第一次请求对象时创建对象,然后就将对象保留在对象池中。当不用初始或最大容量构建PoolManager时,执行ObjectManager.increasePoolSize()就可以指定对象池的容量——因为当对象池空了时,它是从PoolManager.get()来调用的(见列表2)。

读取对象

列表 2. PoolManager.get()从对象池读取对象,根据需要创建新的对象并加大对象池容量。



PoolManager.get()方法也将未完成的请求数量传递到ObjectManager.increasePoolSize()中,这样你就可以延迟创建新的对象,直到达到一个特定的极限。这就方便了复杂的对象池容量策略的实现。

PoolManager.get()方法查看对象池是否被激活,并增加等待实现的请求数量。它也查看对象池是否是空的。如果还有空间来加大对象池,它就调用ObjectManager.create()来创建新的对象,添加到对象池中并返回给调用者。否则,它调用ObjectManager的increasePoolSize(),传入等待的请求数量。如果对象池仍是空的——因为ObjectManager.increasePoolSize()没有创建新的对象——请求就会被阻塞,直到一个对象被释放回到对象池中。

PoolManager定期调用ObjectManager.decreasePoolSize()来查看是否可以回收对象池中不用的对象。你可以覆盖getDecrementInterval()方法来改变缺省的30分钟的时间间隔。在执行decreasePoolSize()时,得到或释放对象的请求就被阻塞。另外,decreasePoolSize()可以调用shrinkPool()方法,它可以将一个对象移出对象池并提供对它的引用。PoolManager也可以让你刷新对象池中的对象——例如,确保TCP/IP连接没有超时。PoolManager定期(缺省情况下,每隔五分钟)调用ObjectManager.refresh(),传入一个iterator,给对象提供只读访问。在执行ObjectManager.refresh()时,从对象池得到或释放对象的请求会被阻塞。

最后,PoolManager提供hooks(通过PoolReleaseStrategy),在客户端得到对象前可以在对象池中处理对象。这就为我们提供了方便,使我们可以在运用对象前初始化对象,在它们返回对象池前重新设置它们的状态——处理它们。例如,你可以查看数据库事务处理隔离级别(isolation level)或重新设置错误代码。

我们这里讲述的对象池架构具有普遍性,它适合不同应用程序的需要。可以让你控制对象池的容量、对象填充策略和对象状态。一个设计良好的对象池可以极大地提高你的应用程序的效率,不管从速度方面考虑,还是从资源利用率方面考虑,该架构都可以提供这样的好处。

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值