Java 对象池实现完整教程
·
目录

1. 什么是对象池
定义
对象池 (Object Pool) 是一种创建型设计模式,用于管理一组预先初始化好的对象,使用时从池中获取,用完后归还而不是销毁。
为什么需要对象池?
| 问题 | 对象池解决 |
|---|---|
| 对象创建开销大 | 预创建,复用 |
| 创建时间长 | 从池中取,立即可用 |
| 内存碎片 | 减少 GC |
| 限制资源使用 | 控制最大数量 |
生活中的类比
2. 对象池的应用场景
2.1 适合使用的场景
✅ 数据库连接 (Connection Pool)
- 创建连接耗时 (TCP 握手、认证等)
- 连接数有限
✅ 线程池 (Thread Pool)
- 线程创建开销大
- 避免无限创建线程
✅ 网络连接 (HTTP / gRPC)
- 连接建立耗时
- 可复用连接
✅ 大对象 / 复杂对象
- 初始化成本高
- 例如:XML 解析器、加密解密器
✅ 高性能场景
- 低延迟要求
- 高吞吐量要求
2.2 不适合使用的场景
❌ 轻量对象
- 例如:String、StringBuilder
- 对象本身比池管理开销还小
❌ 使用频率极低
- 维护池的成本 > 收益
❌ 线程安全要求极高,难以实现
3. 核心设计思想
3.1 对象池状态机
3.2 核心接口
// 对象工厂 - 负责对象的生命周期管理
interface PooledObjectFactory<T> {
T create(); // 创建对象
void destroy(T obj); // 销毁对象
boolean validate(T obj); // 验证对象是否健康
void activate(T obj); // 激活对象(借出前)
void passivate(T obj); // 钝化对象(归还后)
}
// 对象池
interface ObjectPool<T> {
T borrowObject(); // 从池中借一个对象
void returnObject(T obj); // 归还对象
void invalidateObject(T obj); // 废弃无效对象
int getNumIdle(); // 空闲对象数
int getNumActive(); // 活跃对象数
void close(); // 关闭池
}
3.3 借对象流程图
4. 手写一个简单对象池
4.1 版本 1: 最基础的实现
import java.util.concurrent.BlockingQueue;
import java.util.concurrent.LinkedBlockingQueue;
import java.util.concurrent.atomic.AtomicInteger;
public class SimpleObjectPool<T> {
private final BlockingQueue<T> pool;
private final PooledObjectFactory<T> factory;
private final int maxTotal;
private final AtomicInteger createdCount = new AtomicInteger(0);
public SimpleObjectPool(PooledObjectFactory<T> factory, int maxTotal) {
this.factory = factory;
this.maxTotal = maxTotal;
this.pool = new LinkedBlockingQueue<>(maxTotal);
}
// 借对象
public T borrowObject() throws Exception {
T obj = pool.poll();
if (obj != null) {
if (factory.validate(obj)) {
factory.activate(obj);
return obj;
} else {
invalidateObject(obj);
}
}
// 池里没有,尝试创建
if (createdCount.get() < maxTotal) {
synchronized (this) {
if (createdCount.get() < maxTotal) {
T newObj = factory.create();
createdCount.incrementAndGet();
factory.activate(newObj);
return newObj;
}
}
}
// 达到上限,阻塞等待
return pool.take();
}
// 归还对象
public void returnObject(T obj) {
if (obj == null) {
return;
}
try {
if (factory.validate(obj)) {
factory.passivate(obj);
pool.offer(obj);
} else {
invalidateObject(obj);
}
} catch (Exception e) {
invalidateObject(obj);
}
}
// 废弃对象
public void invalidateObject(T obj) {
if (obj == null) {
return;
}
try {
factory.destroy(obj);
} finally {
createdCount.decrementAndGet();
}
}
public int getNumIdle() {
return pool.size();
}
public int getNumActive() {
return createdCount.get() - pool.size();
}
public void close() {
pool.forEach(this::invalidateObject);
pool.clear();
}
// 工厂接口
public interface PooledObjectFactory<T> {
T create() throws Exception;
void destroy(T obj) throws Exception;
boolean validate(T obj);
void activate(T obj) throws Exception;
void passivate(T obj) throws Exception;
}
}
4.2 使用示例
// 示例:一个昂贵的对象
class ExpensiveObject {
private String id;
public ExpensiveObject(String id) {
this.id = id;
System.out.println("✅ 创建对象: " + id + " (这很慢...)");
try {
Thread.sleep(1000); // 模拟创建耗时
} catch (InterruptedException e) {}
}
public void doWork() {
System.out.println(" 对象 " + id + " 正在工作...");
}
public String getId() {
return id;
}
}
public class SimplePoolDemo {
public static void main(String[] args) throws Exception {
// 创建工厂
SimpleObjectPool.PooledObjectFactory<ExpensiveObject> factory =
new SimpleObjectPool.PooledObjectFactory<>() {
private int counter = 0;
@Override
public ExpensiveObject create() {
return new ExpensiveObject("Obj-" + (++counter));
}
@Override
public void destroy(ExpensiveObject obj) {
System.out.println("❌ 销毁对象: " + obj.getId());
}
@Override
public boolean validate(ExpensiveObject obj) {
return true; // 简化,总是有效
}
@Override
public void activate(ExpensiveObject obj) {
System.out.println("▶️ 激活对象: " + obj.getId());
}
@Override
public void passivate(ExpensiveObject obj) {
System.out.println("⏸️ 钝化对象: " + obj.getId());
}
};
// 创建池,最大 2 个对象
SimpleObjectPool<ExpensiveObject> pool =
new SimpleObjectPool<>(factory, 2);
System.out.println("=== 第一次借对象 ===");
ExpensiveObject obj1 = pool.borrowObject();
obj1.doWork();
System.out.println("\n=== 第二次借对象 ===");
ExpensiveObject obj2 = pool.borrowObject();
obj2.doWork();
System.out.println("\n=== 归还 obj1 ===");
pool.returnObject(obj1);
System.out.println("\n=== 第三次借对象 (应该复用 obj1) ===");
ExpensiveObject obj3 = pool.borrowObject();
obj3.doWork();
System.out.println("\n=== 状态统计 ===");
System.out.println("空闲: " + pool.getNumIdle());
System.out.println("活跃: " + pool.getNumActive());
// 归还
pool.returnObject(obj2);
pool.returnObject(obj3);
// 关闭池
pool.close();
}
}
4.3 版本 2: 支持更多配置
import java.time.Duration;
public class ObjectPoolConfig {
private int maxTotal = 8; // 最大总数
private int maxIdle = 8; // 最大空闲
private int minIdle = 0; // 最小空闲
private Duration maxWaitDuration = Duration.ofSeconds(10); // 最大等待时间
private Duration timeBetweenEvictionRuns = Duration.ofMinutes(1); // 清理间隔
private boolean testOnBorrow = true; // 借时验证
private boolean testOnReturn = false; // 还时验证
private boolean testWhileIdle = true; // 空闲时验证
// getters and setters...
}
5. Apache Commons Pool2 (业界标准)
5.1 Commons Pool2 架构
5.2 引入依赖
<dependency>
<groupId>org.apache.commons</groupId>
<artifactId>commons-pool2</artifactId>
<version>2.12.0</version>
</dependency>
5.3 使用示例
import org.apache.commons.pool2.BasePooledObjectFactory;
import org.apache.commons.pool2.PooledObject;
import org.apache.commons.pool2.impl.DefaultPooledObject;
import org.apache.commons.pool2.impl.GenericObjectPool;
import org.apache.commons.pool2.impl.GenericObjectPoolConfig;
// 1. 定义工厂
class ExpensiveObjectFactory extends BasePooledObjectFactory<ExpensiveObject> {
private int counter = 0;
@Override
public ExpensiveObject create() {
return new ExpensiveObject("Obj-" + (++counter));
}
@Override
public PooledObject<ExpensiveObject> wrap(ExpensiveObject obj) {
return new DefaultPooledObject<>(obj);
}
@Override
public void destroyObject(PooledObject<ExpensiveObject> p) {
System.out.println("❌ 销毁: " + p.getObject().getId());
}
@Override
public boolean validateObject(PooledObject<ExpensiveObject> p) {
return true;
}
@Override
public void activateObject(PooledObject<ExpensiveObject> p) {
System.out.println("▶️ 激活: " + p.getObject().getId());
}
@Override
public void passivateObject(PooledObject<ExpensiveObject> p) {
System.out.println("⏸️ 钝化: " + p.getObject().getId());
}
}
// 2. 使用池
public class CommonsPoolDemo {
public static void main(String[] args) throws Exception {
// 配置
GenericObjectPoolConfig<ExpensiveObject> config =
new GenericObjectPoolConfig<>();
config.setMaxTotal(10);
config.setMaxIdle(5);
config.setMinIdle(1);
config.setMaxWait(Duration.ofSeconds(5));
config.setTestOnBorrow(true);
// 创建池
ExpensiveObjectFactory factory = new ExpensiveObjectFactory();
GenericObjectPool<ExpensiveObject> pool =
new GenericObjectPool<>(factory, config);
// 使用
ExpensiveObject obj = pool.borrowObject();
try {
obj.doWork();
} finally {
pool.returnObject(obj);
}
pool.close();
}
}
6. Netty 对象池 (高性能场景)
Netty 有自己的轻量级对象池实现,用于频繁分配的对象 (如 ByteBuf)。
6.1 Recycler
import io.netty.util.Recycler;
class MyObject {
private static final Recycler<MyObject> RECYCLER = new Recycler<>() {
@Override
protected MyObject newObject(Handle<MyObject> handle) {
return new MyObject(handle);
}
};
private final Recycler.Handle<MyObject> handle;
private MyObject(Recycler.Handle<MyObject> handle) {
this.handle = handle;
}
public static MyObject newInstance() {
return RECYCLER.get();
}
public void recycle() {
handle.recycle(this);
}
// 业务数据
private String data;
public void setData(String data) { this.data = data; }
public String getData() { return data; }
}
// 使用
public class NettyRecyclerDemo {
public static void main(String[] args) {
MyObject obj = MyObject.newInstance();
obj.setData("Hello");
System.out.println(obj.getData());
obj.recycle(); // 归还
// 再次获取 (可能复用之前的对象)
MyObject obj2 = MyObject.newInstance();
System.out.println(obj2.getData()); // 可能还是 "Hello" (取决于实现)
}
}
7. 最佳实践
7.1 调优参数
| 参数 | 建议 | 说明 |
|---|---|---|
| maxTotal | 2-8 x CPU | 根据实际压测 |
| maxIdle | = maxTotal 或略小 | 避免频繁创建销毁 |
| minIdle | 1-2 | 保持少量预热 |
| maxWait | 不要太长 | 避免无限等待 |
7.2 常见坑
❌ 忘记归还对象 → 泄漏
// 错误示范
ExpensiveObject obj = pool.borrowObject();
obj.doWork();
// 忘记 returnObject!
✅ 正确做法
ExpensiveObject obj = null;
try {
obj = pool.borrowObject();
obj.doWork();
} finally {
if (obj != null) {
pool.returnObject(obj);
}
}
❌ 归还后继续使用 → 并发问题
❌ 对象状态没有清理 → 污染下一个使用者
7.3 监控
// 建议监控指标
- getNumActive() // 活跃数
- getNumIdle() // 空闲数
- borrow 等待时间
- 对象创建频率
总结
- 对象池 = 空间换时间
- 不是所有对象都需要池化
- 推荐用 Apache Commons Pool2
- 一定要用 try-finally 确保归还
- 做好监控,防止泄漏
更多推荐


所有评论(0)