How to Extend Commons‑Pool2 for Custom KeyedObjectPool Idle Management
This article explains why the default Apache Commons‑Pool2 APIs cannot limit idle objects per key, and demonstrates three practical techniques—scheduled cleanup, factory modification, and priority‑based eviction—to enforce per‑key idle limits in a GenericKeyedObjectPool implementation.
Requirement
The overall pool has a fixed maximum size due to hardware constraints, but each KeyedPool must keep objects alive for high‑frequency short‑term calls. Creating objects is expensive, so they cannot be destroyed immediately after use. The author set minIdle=0, maxIdle=5, and maxTotal=10, but observed that concurrent access leaves many idle objects consuming resources.
APIs Used
Commons‑Pool2 does not expose an API to set a maximum idle time per KeyedPool. Consequently, objects are only reclaimed when a per‑key idle limit or the global pool limit is reached, which does not satisfy the need to keep at most one idle object per key.
To implement the desired behavior, the following internal APIs are required:
org.apache.commons.pool2.impl.GenericKeyedObjectPool#getNumIdle(K key)– returns the current idle count for a specific key.
org.apache.commons.pool2.impl.GenericKeyedObjectPool#getNumActivePerKey()– returns a map of active object counts per key.
org.apache.commons.pool2.impl.GenericKeyedObjectPool#getNumWaitersByKey(K key)– provides the number of waiting threads per key.
org.apache.commons.pool2.impl.GenericKeyedObjectPool#listAllObjects()– lists all objects in the pool.
Object Destruction
To actively destroy objects, the pool uses org.apache.commons.pool2.impl.GenericKeyedObjectPool#destroy. Two cleanup APIs are available: GenericKeyedObjectPool#clear(K key) – clears all objects for a specific key. GenericKeyedObjectPool#invalidateObject(K key, T obj) – destroys a single object.
The author prefers the second method: borrow the object, then invalidate it. Direct private‑field manipulation via reflection is also possible but omitted here.
Implementation Ideas
Approach 1 – Scheduled Cleanup
Run a periodic task that scans all KeyedPool instances, identifies excess idle objects, borrows them, and destroys them using the APIs above.
Approach 2 – Factory Modification
Extend org.apache.commons.pool2.BaseKeyedPooledObjectFactory and add custom logic in the creation and destruction hooks. When creating an object in ParagonClientPool.FunTester#create, mark the first object of each key and store its state in a shared data map. In ParagonClientPool.FunTester#destroyObject, check the mark and update the map, destroying objects that are unmarked and expired.
Approach 3 – Priority‑Based Eviction
Introduce a priority scheme for keys. High‑priority keys are allowed up to two idle objects to guarantee concurrency, while low‑priority keys are forced to zero idle objects after the maximum idle time expires, freeing resources for the high‑priority pools.
These three strategies provide flexible ways to enforce per‑key idle limits, improve resource utilization, and maintain high‑throughput access patterns in a shared GenericKeyedObjectPool environment.
Signed-in readers can open the original source through BestHub's protected redirect.
This article has been distilled and summarized from source material, then republished for learning and reference. If you believe it infringes your rights, please contactand we will review it promptly.
How this landed with the community
Was this worth your time?
0 Comments
Thoughtful readers leave field notes, pushback, and hard-won operational detail here.
