这里以commons-pool2来进行测试,它的本质是使用阻塞队列 class LinkedBlockingDeque extends AbstractQueue implements Deque, Serializable 来管理空闲对象。这个队列支持线程安全的入队和出队操作,确保在多线程环境下对象的取用和归还是同步的
<dependency>
<groupId>org.apache.commons</groupId>
<artifactId>commons-pool2</artifactId>
<version>2.12.0</version>
</dependency>
public class User {
private String name;
private int age;
private String address;
}
public static ObjectPool<User> getObjectPool() {
GenericObjectPoolConfig<User> config = new GenericObjectPoolConfig<>();
config.setMaxTotal(10); // 最大对象数
config.setMaxIdle(5); // 最大空闲对象数
config.setMinIdle(2); // 最小空闲对象数
config.setTestOnBorrow(true); // borrow 对象时进行检测
config.setTestOnReturn(true); // return 对象时进行检测
config.setTestWhileIdle(true); // 空闲时进行检测
BasePooledObjectFactory<User> factory = new BasePooledObjectFactory<User>() {
@Override
public User create() throws Exception {
return new User();
}
@Override
public PooledObject<User> wrap(User user) {
return new DefaultPooledObject<>(user);
}
@Override
public boolean validateObject(PooledObject<User> p) {
return true;
}
@Override
public void destroyObject(PooledObject<User> p) {
System.err.println("destroy");
}
};
return new GenericObjectPool<>(factory, config);
}
第一次对比
User user = pool.borrowObject();
user.setName(name);
user.setAge(age);
user.setAddress(address);
pool.returnObject(user);
new User(name, age, address);
输出如下, 可以发现, 直接new的快很多。
49696300
2989000
第二次对比
在User中增加
byte[] bytes = new byte[100 * 1024 * 1024];
这样分配对象的时候,成本就比较大了。
public class User {
private String name;
private int age;
private String address;
byte[] bytes = new byte[100 * 1024 * 1024];
}
从输出结果看,对象池的优势体现的很明显。
65196800
54310277000
对象池
非池
使用 Apache Commons Pool 管理对象池时,并不一定总是比直接使用 new 关键字创建对象来得快。性能的比较取决于多种因素,包括对象的创建成本、池的配置、系统当前的负载情况以及对象的使用模式。
对象池的主要优势在于复用已经创建的对象,减少创建和销毁对象的开销,特别是在对象初始化需要消耗较多资源或时间的情况下(例如数据库连接、线程、网络连接等)。对象池通过减少这些操作,可以提高应用程序的响应速度和吞吐量,同时也减轻垃圾回收的压力。
然而,如果对象的创建成本很低,或者对象池的配置不合理(例如池太小,导致频繁的等待和上下文切换),那么直接创建新对象可能会更快。此外,如果对象池中的所有对象都处于使用中,那么请求对象时仍然需要等待新对象的创建。