Home/Learn/Low Level Design/Object Pool Pattern

Object Pool Pattern

Advanced
Creational Patterns

Manages 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.

Java — Generic Object Pool + Connection Pool
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.

YAML + Java — HikariCP pool configuration
# 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 Aria
1

How does a connection pool prevent resource exhaustion?

EasyAmazon
2

What happens in HikariCP when maximumPoolSize connections are all in use?

MediumUber
3

How do you handle stale connections in an object pool?

MediumNetflix
4

What is the difference between minimumIdle and maximumPoolSize in HikariCP?

EasyFlipkart
5

Design a thread pool from scratch — what data structures would you use?

HardGoogle

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.

Loading discussion…