对象池化,是目前非常常用的一种系统优化技术。它的核心思想是:如果一个类被频繁请求使用,那么不必每次都生成一个实例,可以将这个类的一些实例保存在一个"池"中,待需要使用的时候直接从池中获取。这个"池"就称为对象池
在实现细节上,它可能是一个数组,一个链表或者任何集合类
对象池的使用非常广泛,其中最熟悉的,就是线程池和数据库连接池
线程池
线程池中保存着可以被重用的线程对象,当有任务被提交到线程池中,系统并不需要新建线程,而是从线程池中获取一个可用的线程执行这个任务。在任务结束后,也不关闭线程,而是将它返回到线程池中,以便下次继续使用。
由于线程的创建和销毁是较为费时的工作,因此在线程调度频繁的系统中,线程池可以很好地改善性能
数据库连接池
数据库连接池是一种特殊的对象池,它用于维护数据库连接的集合。当系统需要访问数据库时,不需要重新建立数据库连接,而可以直接从池中取出;在数据库操作完成后,也不关闭数据库连接,而是将连接返回到连接池中。
由于数据库连接的创建和销毁是重量级的操作,因此避免频繁进行这两个操作,对改善系统的性能有积极的意义
Druid连接池配置
<bean id="dataSource" class="com.alibaba.druid.pool.DruidDataSource">
<property name="driverClassName" value="${jdbc.driverClassName}"/>
<property name="url" value="${jdbc.url}"/>
<property name="username" value="${jdbc.username}"/>
<property name="password" value="${jdbc.password}"/>
<property name="initialSize" value="${jdbc.initialSize}"/>
</bean>
dataSources.properties文件
jdbc.driverClassName=com.mysql.jdbc.Driver
jdbc.url=jdbc:mysql://localhost:3306/ssm?useUnicde=true&characterEncoding=utf-8
jdbc.username=root
jdbc.password=
jdbc.initialSize=5
扩展
除了线程池和数据库连接池,对于普通的Java对象,在必要时可也以进行池化管理。对于那些经常使用,并且创建很费时的大型对象来说,使用对象池维护,不仅可以节省获得对象实例的成本,还可以减轻GC频繁回收这些对象产生的系统压力。但是对于生成对象开销很小的对象进行池化,反而可能得不偿失,维护对象池的成本可能会大于对象池带来的好处
在实际开发中,Apache已经提供了一个Jakarta Commons Pool对象池组件,可以直接使用
// Jakarta Commons Pool定义的对象池接口
public interface ObjectPool {
Object borrowObject() throws Exception, NoSuchElementException, IllegalStateException;
void returnObject(Object var1) throws Exception;
void invalidateObject(Object var1) throws Exception;
void addObject() throws Exception, IllegalStateException, UnsupportedOperationException;
int getNumIdle() throws UnsupportedOperationException;
int getNumActive() throws UnsupportedOperationException;
void clear() throws Exception, UnsupportedOperationException;
void close() throws Exception;
void setFactory(PoolableObjectFactory var1) throws IllegalStateException, UnsupportedOperationException;
}
// 另一个重要接口,告诉对象池如何创建一个对象,如何销毁一个对象
public interface PoolableObjectFactory {
Object makeObject() throws Exception; // 定义如何创建一个新的对象实例
void activateObject(Object var1) throws Exception; // 在对象从对象池取出钱,会激活这对象
void passivateObject(Object var1) throws Exception; // 在对象返回对象池时被调用
void destroyObject(Object var1) throws Exception; // 对象从对象池中被销毁时,会执行这个方法
boolean validateObject(Object var1); // 判断对象是否可用
}
下面这段代码显示了一个简单的对象池工厂
public class PoolableObjectFactoryDemo implements PoolableObjectFactory {
private static AtomicInteger counter = new AtomicInteger(0);
@Override
public Object makeObject() throws Exception { // 创建对象
Object obj = String.valueOf(counter.getAndIncrement());
System.out.println("Create Object:" + obj);
return obj;
}
@Override
public void activateObject(Object obj) throws Exception { // 在被取出前调用
System.out.println("Before borrow:" + obj);
}
@Override
public void passivateObject(Object obj) throws Exception { // 当对象返回池中时被调用
System.out.println("return:" + obj);
}
@Override
public boolean validateObject(Object obj) {
return true;
}
@Override
public void destroyObject(Object obj) throws Exception { // 对象被销毁时调用
System.out.println("Destroying Object:" + obj);
}
}
public class ObjectPoolDemo {
static PoolableObjectFactory factory = new PoolableObjectFactoryDemo();
static ObjectPool pool = new GenericObjectPool(factory);
private static AtomicInteger endcount = new AtomicInteger(0);
public static class PoolThread extends Thread {
@Override
public void run() {
Object obj = null;
try {
for (int i = 0; i < 10; i++) {
System.out.println("== " + i + " ==");
obj = pool.borrowObject();
System.out.println(obj + " is get");
pool.returnObject(obj);
}
} catch (Exception e) {
e.printStackTrace();
} finally {
endcount.getAndIncrement();
}
}
}
public static void main(String[] args) {
new PoolThread().start();
new PoolThread().start();
new PoolThread().start();
try {
while (true) {
if (endcount.get() == 3) { // 等待三个线程全部结束
pool.close();
break;
}
}
} catch (Exception e) {
}
}
}
// 运行结果
== 0 ==
== 0 ==
== 0 ==
Create Object:1
Create Object:0
Create Object:2
Before borrow:1
1 is get
return:1
== 1 ==
Before borrow:1
1 is get
return:1
== 2 ==
Before borrow:1
1 is get
return:1
== 3 ==
Before borrow:1
1 is get
return:1
== 4 ==
Before borrow:1
1 is get
return:1
== 5 ==
Before borrow:1
1 is get
return:1
Before borrow:2
Before borrow:0
0 is get
return:0
== 1 ==
Before borrow:0
0 is get
return:0
== 2 ==
Before borrow:0
0 is get
return:0
== 3 ==
Before borrow:0
0 is get
return:0
== 4 ==
Before borrow:0
0 is get
return:0
== 5 ==
Before borrow:0
0 is get
return:0
2 is get
return:2
== 1 ==
Before borrow:2
2 is get
return:2
== 2 ==
Before borrow:2
2 is get
return:2
== 3 ==
Before borrow:2
2 is get
return:2
== 4 ==
Before borrow:2
2 is get
return:2
== 5 ==
Before borrow:2
2 is get
return:2
Destroying Object:2
Destroying Object:0
Destroying Object:1
可以看到,在3个线程向对象池获取对象的过程中,一共建立了3个对象。这3个对象不停地复用,当对象池被关闭时,使用了对象池工厂的destroyObject()方法,销毁对象,释放资源
注:只有重量级对象使用对象池技术才能提高系统性能,对轻量级的对象使用对象池,可能反而会降低系统性能