Backend Development 15 min read

Understanding Java Connection Pools: Commons Pool 2, Jedis, and HikariCP Performance

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

Java Architect Essentials
Java Architect Essentials
Java Architect Essentials
Understanding Java Connection Pools: Commons Pool 2, Jedis, and HikariCP Performance

In Java applications, creating and destroying expensive resources such as threads, database connections, or TCP sockets can significantly impact performance, so pooling these objects allows reuse after lightweight reset.

The Commons Pool 2 library provides a generic object pool implementation. Adding the Maven dependency:

<dependency>
    <groupId>org.apache.commons</groupId>
    <artifactId>commons-pool2</artifactId>
    <version>2.11.1</version>
</dependency>

The core class GenericObjectPool is created with a PooledObjectFactory and a GenericObjectPoolConfig :

public GenericObjectPool(final PooledObjectFactory
factory, final GenericObjectPoolConfig
config)

Jedis, a Redis client, uses Commons Pool 2 via JedisFactory . The key method makeObject creates a Jedis instance, connects it, and returns a DefaultPooledObject<Jedis> :

@Override
public PooledObject
makeObject() throws Exception {
    Jedis jedis = null;
    try {
        jedis = new Jedis(jedisSocketFactory, clientConfig);
        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;
    }
}

The pool obtains objects via borrowObject , first trying the idle queue and creating a new instance if none are available:

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

Objects are stored in a LinkedBlockingDeque , a double‑ended queue.

The main configuration properties of GenericObjectPoolConfig include maxTotal , maxIdle , minIdle , maxWaitMillis , eviction settings, and test flags. Proper tuning of these parameters (especially maxTotal and maxWaitMillis ) is crucial for performance and stability.

Interview questions often focus on appropriate timeout values; a typical recommendation is 500‑1000 ms for services that should respond within 10 ms under normal load.

A JMH benchmark comparing pooled versus non‑pooled Redis operations shows roughly a 5× throughput increase 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();
    }
}

HikariCP, the default Spring Boot 2.x connection pool, achieves high performance through three main techniques:

Replacing ArrayList with FastList to reduce bounds checks.

Bytecode optimization using Javassist, swapping invokevirtual for invokestatic .

Implementing a lock‑free ConcurrentBag to minimize contention.

Key configuration parameters are maximumPoolSize and minimumIdle . In practice, 20‑50 database connections are sufficient for most workloads; setting the pool size excessively large can degrade performance.

HikariCP relies on Connection.isValid() for health checks, avoiding many of the test flags present in Commons Pool.

The article also introduces the concept of a "Result Cache Pool", where the result of expensive operations is cached similarly to object pooling, improving latency for repeated accesses.

In summary, object pooling (for Redis, JDBC, HTTP, RPC, etc.) reduces creation cost, improves throughput, and, when combined with proper configuration and monitoring, can dramatically enhance system performance.

JavaperformanceConnection PoolJedisHikariCPJMHCommons Pool
Java Architect Essentials
Written by

Java Architect Essentials

Committed to sharing quality articles and tutorials to help Java programmers progress from junior to mid-level to senior architect. We curate high-quality learning resources, interview questions, videos, and projects from across the internet to help you systematically improve your Java architecture skills. Follow and reply '1024' to get Java programming resources. Learn together, grow together.

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.