Backend Development 9 min read

Implementing a Process Pool with Apache Commons GenericObjectPool in Java

This article explains how to use Apache Commons GenericObjectPool to implement a reusable process pool in Java, covering the underlying concepts, required dependencies, custom factory implementation, pool configuration, and example code for borrowing and returning pooled objects.

Architect
Architect
Architect
Implementing a Process Pool with Apache Commons GenericObjectPool in Java

1. Introduction

As Java developers, pooling techniques such as thread pools and connection pools are frequently used in business code. Because the Java ecosystem provides mature tools for these techniques, developers can leverage them to improve performance.

When a thread pool is needed, Spring’s ThreadPoolTaskExecutor is often chosen; it manages thread lifecycles and task states internally.

Thread Pool Operation Diagram

2. Main Content

In the author’s scenario, a Java service launches a special process via the command line, which is destroyed after use. Because the overall startup time of this process is performance‑critical, the author proposes pooling the processes to avoid repeated startup overhead.

Understanding GenericObjectPool

The concept of pooling is familiar, but implementing a custom pool from scratch can be difficult. Apache Commons provides GenericObjectPool , a helper for building custom object pools (e.g., JedisPool is built with it).

The constructor of GenericObjectPool takes three parameters; only PooledObjectFactory is mandatory.

/**
 * Creates a new {@code GenericObjectPool} that tracks and destroys
 * objects that are checked out, but never returned to the pool.
 *
 * @param factory   The object factory to be used to create object instances
 *                  used by this pool
 * @param config    The base pool configuration to use for this pool instance.
 *                  The configuration is used by value. Subsequent changes to
 *                  the configuration object will not be reflected in the
 *                  pool.
 * @param abandonedConfig  Configuration for abandoned object identification
 *                         and removal.  The configuration is used by value.
 */
public GenericObjectPool(final PooledObjectFactory
factory,
        final GenericObjectPoolConfig
config, final AbandonedConfig abandonedConfig) {
}

PooledObjectFactory is responsible for creating, validating, activating, and destroying objects in the pool.

void activateObject(PooledObject
p) throws Exception;

void destroyObject(PooledObject
p) throws Exception;

PooledObject
makeObject() throws Exception;

void passivateObject(PooledObject
p) throws Exception;

boolean validateObject(PooledObject
p);

Using GenericObjectPool

First, add the Maven dependency:

<dependency>
   <groupId>org.apache.commons</groupId>
   <artifactId>commons-pool2</artifactId>
   <version>${version}</version>
</dependency>

Implement PooledObjectFactory for the specific business object. In the author’s case, the object is a custom MyProcess representing the external process.

public class MyProcessFactory implements PooledObjectFactory
{
    @Override
    public void destroyObject(PooledObject
p) throws Exception {
        final MyProcess process = p.getObject();
        if (null != process) {
            // destroy process
            process.stop();
        }
    }

    @Override
    public PooledObject
makeObject() throws Exception {
        // create a new process
        MyProcess process = new MyProcess();
        process.start();
        return new DefaultPooledObject<>(process);
    }

    // other methods (activateObject, passivateObject, validateObject) can be implemented as needed
}

Next, build the pool instance:

PooledObjectFactory
factory = new MyProcessFactory();
GenericObjectPool
pool = new GenericObjectPool(factory);

Borrow and return objects from the pool:

// get a process instance
MyProcess process = pool.borrowObject();

// return the instance
pool.returnObject(process);

Advanced Usage of GenericObjectPoolConfig

GenericObjectPoolConfig configures core parameters such as max total, max idle, and min idle. Its superclass BaseObjectPoolConfig adds further options like idle object eviction and LIFO ordering.

/** The default value for the {@code maxTotal} configuration attribute. */
public static final int DEFAULT_MAX_TOTAL = 8;
/** The default value for the {@code maxIdle} configuration attribute. */
public static final int DEFAULT_MAX_IDLE = 8;
/** The default value for the {@code minIdle} configuration attribute. */
public static final int DEFAULT_MIN_IDLE = 0;

Example configuration that keeps up to four processes alive:

private GenericObjectPoolConfig
genericObjectPoolConfig() {
    final GenericObjectPoolConfig
config = new GenericObjectPoolConfig<>();
    config.setMaxTotal(20); // maximum pool size
    config.setMaxIdle(4);   // maximum idle objects
    config.setMinIdle(0);   // minimum idle objects
    config.setMaxWait(Duration.ofSeconds(5)); // max wait time for borrowing
    config.setTimeBetweenEvictionRuns(Duration.ofMinutes(1)); // idle check interval
    config.setMinEvictableIdleTime(Duration.ofMinutes(10)); // min idle time before eviction
    config.setTestOnBorrow(true);
    config.setLifo(false);
    return config;
}

3. Follow‑up

In real projects, additional business logic may be interleaved, but the above sections cover the essential steps for building and configuring a custom object pool, achieving the intended performance optimization.

backendJavaPerformanceSpringGenericObjectPoolObject pool
Architect
Written by

Architect

Professional architect sharing high‑quality architecture insights. Topics include high‑availability, high‑performance, high‑stability architectures, big data, machine learning, Java, system and distributed architecture, AI, and practical large‑scale architecture case studies. Open to ideas‑driven architects who enjoy sharing and learning.

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.