Backend Development 14 min read

Java Connection Pooling: Commons Pool 2, Jedis, and HikariCP

This article explains the principles of object pooling in Java, introduces the Commons Pool 2 library, demonstrates its use with Redis client Jedis, compares performance with JMH benchmarks, and discusses the high‑performance HikariCP database connection pool, including configuration tips and interview questions.

Selected Java Interview Questions
Selected Java Interview Questions
Selected Java Interview Questions
Java Connection Pooling: Commons Pool 2, Jedis, and HikariCP

In typical Java applications, creating expensive resources such as threads, database connections, or TCP sockets repeatedly can cause significant performance loss; pooling these objects allows them to be reused after a lightweight reset.

The article first introduces the widely used Apache Commons Pool 2 library, showing how to add it via Maven:

org.apache.commons
commons-pool2
2.11.1

The core class GenericObjectPool creates a pool by receiving a PooledObjectFactory and a GenericObjectPoolConfig :

public GenericObjectPool(
        final PooledObjectFactory
factory,
        final GenericObjectPoolConfig
config)

As a concrete example, the Redis client Jedis uses Commons Pool to manage its connections. The factory class implements makeObject to create a PooledObject wrapped by new DefaultPooledObject<>(obj) :

@Override
public PooledObject
makeObject() throws Exception {
    Jedis jedis = null;
    try {
        jedis = new Jedis(jedisSocketFactory, clientConfig);
        // time‑consuming operations
        jedis.connect();
        return new DefaultPooledObject<>(jedis);
    } catch (JedisException je) {
        if (jedis != null) {
            try { jedis.quit(); } catch (RuntimeException e) { logger.warn("Error while QUIT", e); }
            try { jedis.close(); } catch (RuntimeException e) { logger.warn("Error while close", e); }
        }
        throw je;
    }
}

When a client borrows an object, the pool first tries to poll an idle instance from a LinkedBlockingDeque ; if none is available it creates a new one via the factory:

public T borrowObject(final Duration borrowMaxWaitDuration) throws Exception {
    // omitted lines
    while (p == null) {
        create = false;
        // try to get from idle queue
        p = idleObjects.pollFirst();
        if (p == null) {
            p = create();
            if (p != null) { create = true; }
        }
        // omitted lines
    }
    // omitted lines
}

The configuration class GenericObjectPoolConfig contains many parameters, such as maxTotal , maxIdle , minIdle , maxWaitMillis , blockWhenExhausted , and several test* flags that control validation on create, borrow, return, and idle checks.

private int maxTotal = DEFAULT_MAX_TOTAL;
private int maxIdle = DEFAULT_MAX_IDLE;
private int minIdle = DEFAULT_MIN_IDLE;
private boolean lifo = DEFAULT_LIFO;
private boolean fairness = DEFAULT_FAIRNESS;
private long maxWaitMillis = DEFAULT_MAX_WAIT_MILLIS;
private long minEvictableIdleTimeMillis = DEFAULT_MIN_EVICTABLE_IDLE_TIME_MILLIS;
private long softMinEvictableIdleTimeMillis = DEFAULT_SOFT_MIN_EVICTABLE_IDLE_TIME_MILLIS;
private int numTestsPerEvictionRun = DEFAULT_NUM_TESTS_PER_EVICTION_RUN;
private boolean testOnCreate = DEFAULT_TEST_ON_CREATE;
private boolean testOnBorrow = DEFAULT_TEST_ON_BORROW;
private boolean testOnReturn = DEFAULT_TEST_ON_RETURN;
private boolean testWhileIdle = DEFAULT_TEST_WHILE_IDLE;
private long timeBetweenEvictionRunsMillis = DEFAULT_TIME_BETWEEN_EVICTION_RUNS_MILLIS;
private boolean blockWhenExhausted = DEFAULT_BLOCK_WHEN_EXHAUSTED;

Typical interview questions focus on setting timeout values ( maxWaitMillis ) and eviction parameters ( minEvictableIdleTimeMillis , softMinEvictableIdleTimeMillis ) to balance resource usage and responsiveness.

A JMH benchmark compares pooled versus non‑pooled Redis access, showing roughly a 5× throughput improvement when using a pool:

@Fork(2)
@State(Scope.Benchmark)
@Warmup(iterations = 5, time = 1)
@Measurement(iterations = 5, time = 1)
@BenchmarkMode(Mode.Throughput)
public class JedisPoolVSJedisBenchmark {
    JedisPool pool = new JedisPool("localhost", 6379);

    @Benchmark
    public void testPool() {
        Jedis jedis = pool.getResource();
        jedis.set("a", UUID.randomUUID().toString());
        jedis.close();
    }

    @Benchmark
    public void testJedis() {
        Jedis jedis = new Jedis("localhost", 6379);
        jedis.set("a", UUID.randomUUID().toString());
        jedis.close();
    }
    // omitted lines
}

The article then shifts to the database connection pool HikariCP, which is the default pool in Spring Boot. HikariCP achieves high performance through three main techniques: using FastList instead of ArrayList , byte‑code optimization with Javassist (replacing invokevirtual with invokestatic ), and a lock‑free ConcurrentBag .

Key configuration parameters for HikariCP include maximumPoolSize and minimumIdle . In practice, a pool size of 20‑50 connections is sufficient for most databases; setting it excessively high can waste resources.

HikariCP relies on Connection.isValid() for health checks, eliminating the need for the many test* flags present in other pools.

The concept of a "Result Cache Pool" is introduced, highlighting the similarity between pooling and caching: both store processed objects for faster subsequent access.

Finally, the article summarizes the main points: object pooling reduces creation cost, proper configuration of pool size and timeout is essential, monitoring pool metrics is crucial, and the same pooling ideas apply to HTTP clients, RPC frameworks, and thread pools.

JavaPerformanceConnection PoolJedisHikariCPJMHCommons Pool
Selected Java Interview Questions
Written by

Selected Java Interview Questions

A professional Java tech channel sharing common knowledge to help developers fill gaps. Follow us!

0 followers
Reader feedback

How this landed with the community

login Sign in to like

Rate this article

Was this worth your time?

Sign in to rate
Discussion

0 Comments

Thoughtful readers leave field notes, pushback, and hard-won operational detail here.