Design Pattern

Object Pool Pattern

Clean Java-only production-ready implementation.


Creating objects (DB connections, threads, sockets) is expensive. Instead of creating and destroying them per request, maintain a pool of reusable objects. Borrow, use, return.

// ─── EXAMPLE 1 ──────────────────────────────────────────────────────────────
// WHAT WE ARE IMPLEMENTING:
// A database connection manager reusing a static set of heavy socket
// connections.
//
// WHERE THE PATTERN FITS IN:
// DatabaseConnectionPool acts as the Pool manager, tracking active and idle
// Connection client instances to throttle load.
// ────────────────────────────────────────────────────────────────────────────
import java.util.concurrent.BlockingQueue;
import java.util.concurrent.LinkedBlockingQueue;
import java.util.concurrent.atomic.AtomicInteger;

// --- Pooled resource ---
class DatabaseConnection {
    private final int id;
    private boolean inUse = false;

    public DatabaseConnection(int id) {
        this.id = id;
        System.out.println("  [Pool] Creating connection " + id);
    }

    public boolean query(String sql) {
        if (!inUse) throw new IllegalStateException("Connection not checked out");
        System.out.println("  [Conn " + id + "] Executing: " + sql);
        return true;
    }

    void markInUse(boolean inUse) { this.inUse = inUse; }
}

// --- Object Pool ---
class ConnectionPool {
    private final BlockingQueue<DatabaseConnection> available = new LinkedBlockingQueue<>();
    private final AtomicInteger created = new AtomicInteger(0);
    private final int maxSize;

    public ConnectionPool(int maxSize) {
        this.maxSize = maxSize;
        // Pre-warm: create minimum connections
        for (int i = 0; i < Math.min(3, maxSize); i++) {
            available.add(createConnection());
        }
    }

    private DatabaseConnection createConnection() {
        return new DatabaseConnection(created.incrementAndGet());
    }

    public DatabaseConnection borrow() throws InterruptedException {
        DatabaseConnection conn = available.poll();
        if (conn == null) {
            if (created.get() < maxSize) {
                conn = createConnection();
            } else {
                // Wait for a connection to be returned (blocking)
                conn = available.take();
            }
        }
        conn.markInUse(true);
        return conn;
    }

    public void release(DatabaseConnection conn) {
        conn.markInUse(false);
        available.offer(conn);
        System.out.println("  [Pool] Connection " + conn + " returned to pool");
    }

    public int availableCount() { return available.size(); }
}

public class Main {
    public static void main(String[] args) throws InterruptedException {
        ConnectionPool pool = new ConnectionPool(5);

        // Borrow and use
        DatabaseConnection c1 = pool.borrow();
        c1.query("SELECT * FROM users");

        DatabaseConnection c2 = pool.borrow();
        c2.query("INSERT INTO orders ...");

        // Return to pool
        pool.release(c1);
        pool.release(c2);

        System.out.println("Available connections: " + pool.availableCount());
    }
}