Backend Development 6 min read

Performance Testing of Apache Commons Pool2 GenericKeyedObjectPool in Java

This article demonstrates how to implement and benchmark Apache Commons Pool2's GenericKeyedObjectPool in Java, including factory creation, pool configuration, multithreaded performance tests with and without wait times, and analysis of results highlighting scalability limitations.

FunTester
FunTester
FunTester
Performance Testing of Apache Commons Pool2 GenericKeyedObjectPool in Java

In the previous post I evaluated the performance of the generic object pool (GenericObjectPool) from Apache Commons Pool2; this article extends the discussion to the more complex GenericKeyedObjectPool, providing a complete example.

Hardware and software setup is the same as before, so it is omitted.

Pooling Factory

The factory extends org.apache.commons.pool2.BaseKeyedPooledObjectFactory<Integer, FunTesterPooled> . The full source code is shown below:

/**
 * 池化工厂
 */
private static class FunFactory extends BaseKeyedPooledObjectFactory
{

    @Override
    FunTesterPooled create(Integer key) throws Exception {
        def pooled = new FunTesterPooled()
        pooled.setAge(key)
        return pooled
    }

    @Override
    PooledObject
wrap(FunTesterPooled value) {
        return new DefaultPooledObject
(value)
    }

    @Override
    void destroyObject(Integer key, PooledObject
p, DestroyMode destroyMode) throws Exception {
        p.getObject().setAge(0)//资源回收
        super.destroyObject(key, p, destroyMode)
    }
}

Object Pool Initialization

The pool is configured with parameters such as max total, min/max idle per key, and max wait time. The initialization method returns a GenericKeyedObjectPool<Integer, FunTesterPooled> instance.

static def initPool() {
    def config = new GenericKeyedObjectPoolConfig
()
    config.setMaxTotal(thread * 2)
    config.setMinIdlePerKey(10)
    config.setMaxIdlePerKey(100)
    config.setMaxWait(Duration.ofMillis(1000))
    config.setMaxIdlePerKey(thread)
    config.setMaxIdlePerKey(10)
    config.setMinIdlePerKey(2)
    return new GenericKeyedObjectPool
(new FunFactory(), config)
}

Performance Test Cases

The test adds a key parameter to the request and returns objects with the same key. The main method creates the pool, spawns multiple threads, borrows and returns objects, and finally closes the pool.

static GenericKeyedObjectPool
pool

static def desc = "池化框架性能测试"

static int times = 200

static int thread = 3

public static void main(String[] args) {
    this.pool = initPool()
    ThreadBase.COUNT = true
    RUNUP_TIME = 0
    POOL_SIZE = thread
    thread.times {
        pool.addObjects(it, thread)
    }
    output("对象创建完毕 创建数量${pool.getNumIdle()}")
    new Concurrent(new FunTester(), thread, desc).start()
    pool.close()
}

private static class FunTester extends FixedThread {
    FunTester() {
        super(null, times, true)
    }

    @Override
    protected void doing() throws Exception {
        def randomInt = getRandomInt(thread)
        def object = pool.borrowObject(randomInt)
        pool.returnObject(randomInt, object)
    }

    @Override
    FunTester clone() {
        return new FunTester()
    }
}

Test Results

Two scenarios were measured: without waiting and with a 2 ms sleep per operation. The tables below show thread count, execution count, and QPS.

线程数

执行次数(万)

QPS

1

300

189501

2

300

322603

5

300

120334

10

100

96861

20

50

81440

With waiting (2 ms sleep):

线程数

执行次数(k)

单线程QPS

20

10

416

50

10

393

100

5

222

200

2

79

300

2

27

The results indicate that QPS drops sharply as thread count increases, and performance becomes comparable to GenericObjectPool only at low thread counts. The degradation is likely caused by contention on java.util.concurrent.ConcurrentHashMap and other internal structures such as org.apache.commons.pool2.impl.LinkedBlockingDeque and java.util.concurrent.atomic.AtomicLong . Consequently, using an object pool as a simple replacement for object creation is not advisable at high concurrency.

Enjoy testing!

javaBackend Developmentperformance testingObject poolApache Commons Pool2GenericKeyedObjectPool
FunTester
Written by

FunTester

10k followers, 1k articles | completely useless

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.