Object Pool Pattern
AdvancedManages a set of reusable, pre-initialized objects to avoid the overhead of repeated creation and destruction of expensive resources.
Overview
Object Pool maintains a pool of ready-to-use objects (connections, threads, parsers) and lends them to callers on demand. When the caller is done, it returns the object to the pool instead of destroying it. The pool handles creation (when the pool is empty and below max size), validation (before lending a potentially stale object), and eviction (removing idle objects above min size). The canonical Java examples are JDBC connection pools (HikariCP, c3p0) and the JVM's built-in thread pool (ExecutorService). Key parameters: minIdle, maxActive, maxWait, validation query.
Generic Object Pool Implementation
A thread-safe generic pool uses a blocking queue to manage available objects. borrowObject() blocks if the pool is empty (up to timeout). returnObject() validates the object before putting it back.
import java.util.concurrent.ArrayBlockingQueue;
import java.util.concurrent.BlockingQueue;
import java.util.concurrent.TimeUnit;
public class ObjectPool<T> {
private final BlockingQueue<T> pool;
private final PooledObjectFactory<T> factory;
private final int maxSize;
public interface PooledObjectFactory<T> {
T create();
boolean validate(T obj); // check if object is still usable
void destroy(T obj); // cleanup before discard
}
public ObjectPool(PooledObjectFactory<T> factory, int minIdle, int maxSize) {
this.factory = factory;
this.maxSize = maxSize;
this.pool = new ArrayBlockingQueue<>(maxSize);
// Pre-populate with minIdle objects
for (int i = 0; i < minIdle; i++) {
pool.offer(factory.create());
}
}
// Borrow an object — blocks up to timeoutMs
public T borrowObject(long timeoutMs) throws InterruptedException {
T obj = pool.poll(timeoutMs, TimeUnit.MILLISECONDS);
if (obj == null) {
// Pool exhausted — create a new one if below maxSize
obj = factory.create();
} else if (!factory.validate(obj)) {
factory.destroy(obj);
obj = factory.create(); // replace stale object
}
return obj;
}
// Return object to pool
public void returnObject(T obj) {
if (obj != null && factory.validate(obj)) {
if (!pool.offer(obj)) {
factory.destroy(obj); // pool full — discard excess
}
} else if (obj != null) {
factory.destroy(obj);
}
}
public int availableObjects() { return pool.size(); }
}
// Concrete usage: Database Connection Pool
public class ConnectionPool {
private final ObjectPool<java.sql.Connection> pool;
public ConnectionPool(String jdbcUrl, String user, String pass, int min, int max) {
pool = new ObjectPool<>(new ObjectPool.PooledObjectFactory<>() {
@Override
public java.sql.Connection create() {
try { return java.sql.DriverManager.getConnection(jdbcUrl, user, pass); }
catch (Exception e) { throw new RuntimeException("Cannot create connection", e); }
}
@Override
public boolean validate(java.sql.Connection conn) {
try { return !conn.isClosed() && conn.isValid(1); }
catch (Exception e) { return false; }
}
@Override
public void destroy(java.sql.Connection conn) {
try { conn.close(); } catch (Exception ignored) {}
}
}, min, max);
}
public java.sql.Connection borrow() throws InterruptedException {
return pool.borrowObject(5_000);
}
public void release(java.sql.Connection conn) {
pool.returnObject(conn);
}
}HikariCP Configuration (Production)
In production, never implement your own connection pool. HikariCP is the fastest JDBC pool and is Spring Boot's default. Understanding its parameters is crucial for performance tuning interviews.
# application.yml — HikariCP tuning (Spring Boot default pool)
spring:
datasource:
url: jdbc:postgresql://localhost:5432/aicancode
username: ${DB_USER}
password: ${DB_PASS}
hikari:
minimum-idle: 5 # min connections kept alive
maximum-pool-size: 20 # never exceed this
idle-timeout: 600000 # remove idle conn after 10 min
max-lifetime: 1800000 # recycle connections every 30 min
connection-timeout: 30000 # throw after 30s wait
validation-timeout: 5000 # isValid() check timeout
connection-test-query: SELECT 1 # for drivers that don't support isValid()
// Programmatic — using HikariConfig
HikariConfig config = new HikariConfig();
config.setJdbcUrl("jdbc:postgresql://localhost:5432/aicancode");
config.setMaximumPoolSize(20);
config.setMinimumIdle(5);
config.setConnectionTimeout(30_000);
config.addDataSourceProperty("cachePrepStmts", "true");
config.addDataSourceProperty("prepStmtCacheSize", "250");
HikariDataSource ds = new HikariDataSource(config);Key Points to Remember
- 1Object Pool trades memory for speed — pre-allocated objects avoid repeated instantiation overhead.
- 2Always validate borrowed objects before use — connections can become stale (network timeout, DB restart).
- 3Return objects to pool in a finally block (or try-with-resources) to prevent pool starvation.
- 4HikariCP is the Spring Boot default — know its key parameters: maximumPoolSize, minimumIdle, connectionTimeout.
- 5Pool starvation occurs when all objects are borrowed and no timeout causes callers to block indefinitely.
- 6Pool size formula: connections = (core_count * 2) + effective_spindle_count (HikariCP documentation).
Interview Questions
Sign in to ask AriaHow does a connection pool prevent resource exhaustion?
What happens in HikariCP when maximumPoolSize connections are all in use?
How do you handle stale connections in an object pool?
What is the difference between minimumIdle and maximumPoolSize in HikariCP?
Design a thread pool from scratch — what data structures would you use?
Ask Aria about Object Pool Pattern
Your personal AI tutor — ask anything about this concept
Revision Status
Personal Notes
Sign in to save personal notes for this topic.
Discussion
Sign in to join the discussion.