物件池 預先建立並管理一組可重複使用的物件實例。客戶端從池中「借用」物件,用完後「歸還」而非銷毀。適用於:
public class ObjectPool<T> {
private final Stack<T> pool = new Stack<>();
private final Class<T> clazz;
private final PoolConfig config;
private int createdCount = 0;
public ObjectPool(Class<T> clazz, PoolConfig config) {
this.clazz = clazz;
this.config = config;
initialize();
}
private void initialize() {
for (int i = 0; i < config.getMinSize(); i++) {
pool.push(createObject());
}
}
private T createObject() {
try {
createdCount++;
return clazz.getDeclaredConstructor().newInstance();
} catch (Exception e) {
throw new RuntimeException("建立物件失敗", e);
}
}
/** 取得物件(阻塞等待) */
public synchronized T borrowObject(long timeoutMillis) throws InterruptedException {
long deadline = System.currentTimeMillis() + timeoutMillis;
while (pool.isEmpty()) {
if (createdCount < config.getMaxSize()) {
return createObject();
}
long waitTime = deadline - System.currentTimeMillis();
if (waitTime <= 0) return null; // 超時
wait(waitTime);
}
return pool.pop();
}
/** 歸還物件 */
public synchronized void returnObject(T obj) {
if (obj == null) return;
if (clazz.isInstance(obj)) {
pool.push(obj);
notifyAll(); // 喚醒等待執行緒
}
}
/** 關閉池,釋放資源 */
public void close() {
pool.clear();
}
}
public class PoolConfig {
private int minSize = 5; // 初始/最小閒置數
private int maxSize = 20; // 最大物件數
private long maxWaitMillis = 2000; // 取得超時時間
private boolean testOnBorrow = true; // 借出前驗證
// getter/setter 省略
}
public class ObjectPoolManager {
private static final Map<Class<?>, ObjectPool<?>> pools = new ConcurrentHashMap<>();
@SuppressWarnings("unchecked")
public static <T> ObjectPool<T> getPool(Class<T> clazz) {
return (ObjectPool<T>) pools.computeIfAbsent(clazz, k -> new ObjectPool<>(k, new PoolConfig()));
}
@SuppressWarnings("unchecked")
public static <T> ObjectPool<T> getPool(Class<T> clazz, PoolConfig config) {
return (ObjectPool<T>) pools.computeIfAbsent(clazz, k -> new ObjectPool<>(k, config));
}
}
// 取得池
ObjectPool<ExpensiveResource> pool = ObjectPoolManager.getPool(ExpensiveResource.class);
// 借用
ExpensiveResource resource = pool.borrowObject(2000);
if (resource == null) {
throw new RuntimeException("資源耗盡,等待超時");
}
try {
resource.doWork(); // 使用資源
} finally {
// 必須歸還!
pool.returnObject(resource);
}
| 功能 | 實作要點 |
|---|---|
| 閒置物件驗證 | testOnBorrow / testOnReturn / testWhileIdle,失效則重建 |
| 閒置清理執行緒 | 定期掃描超過 minIdleTime 的物件並銷毀,維持池大小 |
| 物件重置 | 歸還前呼叫 reset() 清理狀態,避免髒資料洩漏 |
| JMX/監控指標 | 暴露 activeCount、idleCount、borrowCount、waitTime 等指標 |
| 公平鎖/非公平鎖 | 高併發下選擇 ReentrantLock(true) 避免飢餓 |
GenericObjectPool 功能完備物件池模式以「空間換時間、以管理換可預測性」解決高成本物件頻繁建銷問題。自行實作適合輕量場景或教學;生產系統強烈建議直接使用 Apache Commons Pool 2 或 HikariCP,站在巨人肩膀上避開併發、洩漏、監控等深坑。