Object Pool Pattern: Principles, Apache Commons Pool Implementation, and Practical Use Cases
This article explains the object pool design pattern, its working mechanism, step‑by‑step Java implementation using Apache Commons Pool, advantages, drawbacks, and real‑world scenarios such as web server connection pooling and game object reuse, providing complete code examples.
Introduction
The object pool pattern is a widely used design pattern that improves application performance by reusing costly objects instead of creating new instances each time, especially when object creation is expensive or the number of instances is limited by resources.
Working Mechanism
An object pool maintains a pre‑initialized set of objects that can be borrowed and returned on demand; if a reusable object is available it is handed out, otherwise a new one is created and added to the pool.
Implementation with Apache Commons Pool
1. Add the Maven dependency:
<dependency>
<groupId>org.apache.commons</groupId>
<artifactId>commons-pool2</artifactId>
<version>2.9.0</version>
</dependency>2. Define the object to be pooled (example Foo class):
public class Foo {
private final String username;
public Foo(String username) { this.username = username; }
public String getUsername() { return username; }
}3. Create a factory by extending BasePooledObjectFactory<Foo> :
public class FooPoolObjectFactory extends BasePooledObjectFactory
{
@Override
public Foo create() throws Exception {
return new Foo(String.valueOf(RandomUtils.randomInt(0, 10)));
}
@Override
public PooledObject
wrap(Foo obj) {
return new DefaultPooledObject<>(obj);
}
}4. Implement an eviction policy to periodically check object health:
public class FooEvictionPolicy implements EvictionPolicy
{
@Override
public boolean evict(EvictionConfig config, PooledObject
underTest, int idleCount) {
// TODO: add health‑check logic
return true;
}
}5. Build and configure the pool:
public GenericObjectPool
fooGenericObjectPool() {
GenericObjectPoolConfig
poolConfig = new GenericObjectPoolConfig<>();
poolConfig.setEvictionPolicy(new FooEvictionPolicy());
poolConfig.setBlockWhenExhausted(true);
poolConfig.setJmxEnabled(false);
poolConfig.setMaxWaitMillis(1000 * 10);
poolConfig.setTimeBetweenEvictionRunsMillis(60 * 1000);
poolConfig.setMinEvictableIdleTimeMillis(20 * 1000);
poolConfig.setTestWhileIdle(true);
poolConfig.setTestOnReturn(true);
poolConfig.setTestOnBorrow(true);
poolConfig.setMaxTotal(3);
AbandonedConfig abandonedConfig = new AbandonedConfig();
abandonedConfig.setRemoveAbandonedOnMaintenance(true);
abandonedConfig.setRemoveAbandonedOnBorrow(true);
return new GenericObjectPool<>(new FooPoolObjectFactory(), poolConfig, abandonedConfig);
}6. Borrow and return objects:
private final GenericObjectPool
fooGenericObjectPool = fooGenericObjectPool();
public Foo borrowFoo() throws Exception { return fooGenericObjectPool.borrowObject(); }
public void returnObject(Foo foo) { fooGenericObjectPool.returnObject(foo); }Advantages
Improves performance by reducing creation and destruction overhead.
Provides efficient resource management for shared resources such as DB connections.
Ensures consistency by delivering pre‑initialized objects.
Relatively easy to implement and widely applicable.
Disadvantages
Introduces additional complexity and potential maintenance burden.
Pool management itself adds overhead; improper sizing can negate benefits.
Limited flexibility for highly dynamic workloads.
Requires careful thread‑safety handling.
Risk of resource leaks if objects are not returned.
Application Scenarios
Web Server Example – Managing network sockets or database connections to handle high concurrency.
import java.net.ServerSocket;
import java.net.Socket;
import java.util.concurrent.ArrayBlockingQueue;
import java.util.concurrent.BlockingQueue;
public class ConnectionPool {
private static final int MAX_POOL_SIZE = 10;
private static final int MAX_WAIT_TIME = 5000;
private static final int PORT_NUMBER = 8080;
private final BlockingQueue
pool;
private final ServerSocket serverSocket;
public ConnectionPool() throws Exception {
pool = new ArrayBlockingQueue<>(MAX_POOL_SIZE);
serverSocket = new ServerSocket(PORT_NUMBER);
System.out.println("Server started on port " + PORT_NUMBER);
}
public Socket getConnection() throws Exception {
Socket connection = pool.poll();
if (connection == null) {
try { connection = serverSocket.accept(); }
catch (SocketTimeoutException e) { System.out.println("Timeout waiting for connection."); }
}
return connection;
}
public void returnConnection(Socket connection) {
if (pool.size() < MAX_POOL_SIZE) { pool.offer(connection); }
else { try { connection.close(); } catch (Exception e) {} }
}
public static void main(String[] args) throws Exception {
ConnectionPool cp = new ConnectionPool();
while (true) {
Socket conn = cp.getConnection();
Thread.sleep(5000);
cp.returnConnection(conn);
}
}
}Game Development Example – Reusing frequently created objects such as particles or bullets.
import java.util.ArrayList;
import java.util.List;
public class GameObjectPool {
class GameObject { public void reset() { /* reset state */ } }
private static final int MAX_POOL_SIZE = 10;
private final List
pool;
public GameObjectPool() { pool = new ArrayList<>(MAX_POOL_SIZE); for (int i = 0; i < MAX_POOL_SIZE; i++) pool.add(new GameObject()); }
public GameObject getObject() { GameObject obj = pool.remove(0); obj.reset(); return obj; }
public void returnObject(GameObject obj) { if (pool.size() < MAX_POOL_SIZE) pool.add(obj); }
public static void main(String[] args) {
GameObjectPool gp = new GameObjectPool();
GameObject o1 = gp.getObject();
gp.returnObject(o1);
GameObject o2 = gp.getObject();
gp.returnObject(o2);
}
}Conclusion
The object pool pattern is a powerful technique for improving scalability and reliability by reusing expensive objects, managing shared resources, and limiting creation overhead; when applied correctly it can significantly boost performance in both server‑side and game‑development contexts.
Code Ape Tech Column
Former Ant Group P8 engineer, pure technologist, sharing full‑stack Java, job interview and career advice through a column. Site: java-family.cn
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.