Java Pooling Under High Concurrency: Resource Reuse and Performance Optimization

The article explains Java pooling techniques for high‑concurrency scenarios, introduces Apache Commons Pool 2, demonstrates how to configure dependencies, implement a PooledObjectFactory, create custom eviction policies and statistics, and shows a complete runnable example that highlights resource reuse and performance gains.

Spring Full-Stack Practical Cases
Spring Full-Stack Practical Cases
Spring Full-Stack Practical Cases
Java Pooling Under High Concurrency: Resource Reuse and Performance Optimization

1. Introduction

Pooling technology pre‑allocates and centrally manages resources such as threads, connections, or memory, forming a resource pool for repeated use. This reduces the overhead of frequent creation and destruction, limits resource usage, and improves utilization.

2. Apache Commons Pool

Apache Commons Pool is a mature open‑source pooling framework that provides a standard object‑pool implementation. Version 2.0 rewrites the pooling mechanism, offering better performance, scalability, instance tracking, and monitoring.

3. Practical Example

3.1 Add Dependency

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

3.2 Object‑Pool Factory Interface

public interface PooledObjectFactory<T> {
  void activateObject(PooledObject<T>);
  void destroyObject(PooledObject<T>);
  void destroyObject(PooledObject<T>, DestroyMode);
  PooledObject<T> makeObject();
  void passivateObject(PooledObject<T>);
  boolean validateObject(PooledObject<T>);
}

Key methods:

makeObject : called when a new instance is needed.

activateObject : invoked before borrowing an idle instance.

validateObject : checks whether an instance can be borrowed or returned.

passivateObject : called when returning an instance to the pool.

destroyObject : called when the instance is removed from the pool.

3.3 Custom Object Pool

public class Connection {
  public void connect() { System.out.println("Connection established."); }
  public void disconnect() { System.out.println("Connection closed."); }
}

public class ConnectionPooledObjectFactory extends BasePooledObjectFactory<Connection> {
  @Override
  public Connection create() { return new Connection(); }
  @Override
  public PooledObject<Connection> wrap(Connection conn) { return new DefaultPooledObject<>(conn); }
}

3.4 Test Code

PooledObjectFactory<Connection> factory = new ConnectionPooledObjectFactory();
try (GenericObjectPool<Connection> objectPool = new GenericObjectPool<>(factory)) {
  objectPool.setMinIdle(5);
  objectPool.setMaxTotal(20);
  objectPool.setMaxIdle(10);

  Connection connection1 = objectPool.borrowObject();
  connection1.connect();
  System.err.println("object: %s".formatted(connection1.hashCode()));

  Connection connection2 = objectPool.borrowObject();
  connection2.connect();
  System.err.println("object: %s".formatted(connection2.hashCode()));

  objectPool.returnObject(connection2);
  System.err.println("object: %s".formatted(connection2.hashCode()));

  Connection connection3 = objectPool.borrowObject();
  connection3.connect();
  System.err.println("object: %s".formatted(connection3.hashCode()));
  objectPool.returnObject(connection3);
}

Output shows that the same underlying Connection instance can be reused after being returned to the pool.

4. Advanced Features

4.1 Custom Eviction Policy

public class PackEvictionPolicy implements EvictionPolicy<Connection> {
  @Override
  public boolean evict(EvictionConfig config, PooledObject<Connection> underTest, int idleCount) {
    return config.getIdleSoftEvictDuration().compareTo(underTest.getIdleDuration()) < 0 &&
           config.getMinIdle() < idleCount ||
           config.getIdleEvictDuration().compareTo(underTest.getIdleDuration()) < 0;
  }
}

Configure the pool to use the custom policy:

GenericObjectPool<Connection> objectPool = new GenericObjectPool<>(factory);
objectPool.setEvictionPolicy(new PackEvictionPolicy());

4.2 Statistics and Monitoring

The built‑in statistics allow monitoring of active and idle objects, borrowed count, and waiting threads.

System.err.println("""
  Borrowed instances: %s
  Idle instances: %s
  Total borrowed: %s
  Waiting threads: %s
""".formatted(
  objectPool.getNumActive(),
  objectPool.getNumIdle(),
  objectPool.getBorrowedCount(),
  objectPool.getNumWaiters()));

Sample result:

Borrowed instances: 0
Idle instances: 2
Total borrowed: 3
Waiting threads: 0

5. Visual Flow

An illustration (image) shows the lifecycle of objects within the pool, from creation, activation, validation, passivation, to eviction.

The article concludes that using Apache Commons Pool 2 enables efficient resource reuse and performance optimization in high‑concurrency Java applications.

Original Source

Signed-in readers can open the original source through BestHub's protected redirect.

Sign in to view source
Republication Notice

This article has been distilled and summarized from source material, then republished for learning and reference. If you believe it infringes your rights, please contactadmin@besthub.devand we will review it promptly.

Javaperformance optimizationSpring Bootobject-poolingapache-commons-pool
Spring Full-Stack Practical Cases
Written by

Spring Full-Stack Practical Cases

Full-stack Java development with Vue 2/3 front-end suite; hands-on examples and source code analysis for Spring, Spring Boot 2/3, and Spring Cloud.

0 followers
Reader feedback

How this landed with the community

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.