The object pool pattern is a software creational design pattern that uses a set of initialized objects kept ready to use – a "pool" – rather than allocating and destroying them on demand. A client of the pool will request an object from the pool and perform operations on the returned object. When the client has finished, it returns the object to the pool rather than destroying it; this can be done manually or automatically.
Object pools are primarily used for performance: in some circumstances, object pools significantly improve performance. Object pools complicate object lifetime, as objects obtained from and returned to a pool are not actually created or destroyed at this time, and thus require care in implementation.
operator[]/at()), or comparison (
namespaceWikipedia.Examples;
usingSystem;
usingSystem.Collections.Generic;
// The PooledObject class is the type that is expensive or slow to instantiate,
// or that has limited availability, so is to be held in the object pool.
publicclassPooledObject
{
privateDateTime_createdAt=DateTime.Now;
publicDateTimeCreatedAt=>_createdAt;
publicstringTempData{get;set;}
}
// The Pool class controls access to the pooled objects. It maintains a list of available objects and a
// collection of objects that have been obtained from the pool and are in use. The pool ensures that released objects
// are returned to a suitable state, ready for reuse.
publicstaticclassPool
{
privatestaticList<PooledObject>_available=new();
privatestaticList<PooledObject>_inUse=new();
publicstaticPooledObjectGetObject()
{
lock(_available)
{
if(_available.Count!=0)
{
PooledObjectpo=_available[0];
_inUse.Add(po);
_available.RemoveAt(0);
returnpo;
}
else
{
PooledObjectpo=new();
_inUse.Add(po);
returnpo;
}
}
}
publicstaticvoidReleaseObject(PooledObjectpo)
{
CleanUp(po);
lock(_available)
{
_available.Add(po);
_inUse.Remove(po);
}
}
privatestaticvoidCleanUp(PooledObjectpo)
{
po.TempData=null;
}
}
In the code above, the PooledObject has properties for the time it was created, and another, that can be modified by the client, that is reset when the PooledObject is released back to the pool. Shown is the clean-up process, on release of an object, ensuring it is in a valid state before it can be requested from the pool again.
The following Go code initializes a resource pool of a specified size (concurrent initialization) to avoid resource race issues through channels, and in the case of an empty pool, sets timeout processing to prevent clients from waiting too long.
PooledObjectPool.java:
available = new HashMap<>();\n\tprivate static Map<PooledObject, Long> inUse = new HashMap<>();\n\t\n\tpublic synchronized static PooledObject getObject() {\n\t\tlong now = System.currentTimeMillis();\n\t\tif (!available.isEmpty()) {\n\t\t\tfor (Map.Entry<PooledObject, Long> entry : available.entrySet()) {\n\t\t\t\tif (now - entry.getValue() > EXPIRY_TIME) {\n // object has expired\n\t\t\t\t\tpopElement(available);\n\t\t\t\t} else {\n\t\t\t\t\tPooledObject po = popElement(available, entry.getKey());\n\t\t\t\t\tpush(inUse, po, now); \n\t\t\t\t\treturn po;\n\t\t\t\t}\n\t\t\t}\n\t\t}\n\n\t\t// either no PooledObject is available or each has expired, so return a new one\n\t\treturn createPooledObject(now);\n\t}\t\n\t\n\tprivate synchronized static PooledObject createPooledObject(long now) {\n\t\tPooledObject po = new PooledObject();\n\t\tpush(inUse, po, now);\n\t\treturn po;\n }\n\n\tprivate synchronized static void push(HashMap<PooledObject, Long> map, PooledObject po, long now) {\n\t\tmap.put(po, now);\n\t}\n\n\tpublic static void releaseObject(PooledObject po) {\n\t\tcleanUp(po);\n\t\tavailable.put(po, System.currentTimeMillis());\n\t\tinUse.remove(po);\n\t}\n\t\n\tprivate static PooledObject popElement(HashMap<PooledObject, Long> map) {\n\t\t Map.Entry<PooledObject, Long> entry = map.entrySet().iterator().next();\n\t\t PooledObject key = entry.getKey();\n\t\t // Long value = entry.getValue();\n\t\t map.remove(entry.getKey());\n\t\t return key;\n\t}\n\t\n\tprivate static PooledObject popElement(HashMap<PooledObject, Long> map, PooledObject key) {\n\t\tmap.remove(key);\n\t\treturn key;\n\t}\n\t\n\tpublic static void cleanUp(PooledObject po) {\n\t\tpo.setTemp1(null);\n\t\tpo.setTemp2(null);\n\t\tpo.setTemp3(null);\n\t}\n}\n\n"}}'>packageorg.wikipedia.examples;
importjava.util.HashMap;
importjava.util.Map;
publicclass PooledObjectPool{
publicstaticfinallongEXPIRY_TIME=6000;// 6 seconds
privatestaticMap<PooledObject,Long>available=newHashMap<>();
privatestaticMap<PooledObject,Long>inUse=newHashMap<>();
publicsynchronizedstaticPooledObjectgetObject(){
longnow=System.currentTimeMillis();
if(!available.isEmpty()){
for(Map.Entry<PooledObject,Long>entry:available.entrySet()){
if(now-entry.getValue()>EXPIRY_TIME){
// object has expired
popElement(available);
}else{
PooledObjectpo=popElement(available,entry.getKey());
push(inUse,po,now);
returnpo;
}
}
}
// either no PooledObject is available or each has expired, so return a new one
returncreatePooledObject(now);
}
privatesynchronizedstaticPooledObjectcreatePooledObject(longnow){
PooledObjectpo=newPooledObject();
push(inUse,po,now);
returnpo;
}
privatesynchronizedstaticvoidpush(HashMap<PooledObject,Long>map,PooledObjectpo,longnow){
map.put(po,now);
}
publicstaticvoidreleaseObject(PooledObjectpo){
cleanUp(po);
available.put(po,System.currentTimeMillis());
inUse.remove(po);
}
privatestaticPooledObjectpopElement(HashMap<PooledObject,Long>map){
Map.Entry<PooledObject,Long>entry=map.entrySet().iterator().next();
PooledObjectkey=entry.getKey();
// Long value = entry.getValue();
map.remove(entry.getKey());
returnkey;
}
privatestaticPooledObjectpopElement(HashMap<PooledObject,Long>map,PooledObjectkey){
map.remove(key);
returnkey;
}
publicstaticvoidcleanUp(PooledObjectpo){
po.setTemp1(null);
po.setTemp2(null);
po.setTemp3(null);
}
}
There is a Rust crate called colony which is based on std::hive (or plf::colony) from C++. It has no longer been maintained since January 2024.
"Standard library header <hive> (C++26) - cppreference.com".
cppreference.com. Retrieved 1 October 2025.
↑