NonBlockingPoolpublic class NonBlockingPool extends AbstractPool NonBlockingPool pool provides the basic implementation of an object
pool. The implementation uses a linked list to maintain a list of
(available) objects. If the pool is empty it simply creates one using the
ObjectFactory instance. Subclasses can change this behaviour by overriding
getObject(...) and returnObject(....) methods. This class provides basic
support for synchronization, event notification, pool shutdown
and pool object recycling. It also does some very basic bookkeeping like the
number of objects created, number of threads waiting for object.
Subclasses can make use of these book-keeping data to provide complex
pooling mechanism like LRU / MRU / Random. Also, note that AbstractPool
does not have a notion of pool limit. It is upto to the derived classes
to implement these features. |
Fields Summary |
---|
private String | poolName | private TimerTask | poolTimerTask | protected boolean | addedResizeTask | protected boolean | addedIdleBeanWork | protected boolean | inResizing | private boolean | maintainSteadySize | private int | resizeTaskCount | private int | timerTaskCount |
Constructors Summary |
---|
protected NonBlockingPool()
| public NonBlockingPool(String poolName, ObjectFactory factory, int steadyPoolSize, int resizeQuantity, int maxPoolSize, int idleTimeoutInSeconds, ClassLoader loader)
this.poolName = poolName;
initializePool(factory, steadyPoolSize, resizeQuantity, maxPoolSize,
idleTimeoutInSeconds, loader);
|
Methods Summary |
---|
private void | addResizeTaskForImmediateExecution()
try {
ReSizeWork work = new ReSizeWork();
ContainerWorkPool.addLast(work);
if(_logger.isLoggable(Level.FINE)) {
_logger.log(Level.FINE,
"[Pool-" + poolName + "]: Added PoolResizeTimerTask...");
}
resizeTaskCount++;
} catch (Exception ex) {
synchronized (list) {
addedResizeTask = false;
}
if(_logger.isLoggable(Level.WARNING)) {
_logger.log(Level.WARNING,
"[Pool-"+poolName+"]: Cannot perform "
+ " pool resize task", ex);
}
}
| public void | close()Close the pool
synchronized (list) {
if (poolTimerTask != null) {
try {
poolTimerTask.cancel();
if(_logger.isLoggable(Level.FINE)) {
_logger.log(Level.FINE,
"[Pool-"+poolName+"]: Cancelled pool timer task "
+ " at: " + (new java.util.Date()));
}
} catch (Throwable th) {
//Can safely ignore this!!
}
}
if(_logger.isLoggable(Level.FINE)) {
_logger.log(Level.FINE,"[Pool-"+poolName+"]: Destroying "
+ list.size() + " beans from the pool...");
}
// since we're calling into ejb code, we need to set context
// class loader
ClassLoader origLoader =
Utility.setContextClassLoader(containerClassLoader);
Object[] array = list.toArray();
for (int i=0; i<array.length; i++) {
try {
destroyedCount++;
try {
factory.destroy(array[i]);
} catch (Throwable th) {
_logger.log(Level.FINE, "exception in close", th);
}
} catch (Throwable th) {
_logger.log(Level.WARNING,
"[Pool-"+poolName+"]: Error while destroying", th);
}
}
if(_logger.isLoggable(Level.FINE)) {
_logger.log(Level.FINE,"Pool-"+poolName+"]: Pool closed....");
}
list.clear();
Utility.setContextClassLoader(origLoader);
}
// helps garbage collection
this.list = null;
this.factory = null;
this.poolTimerTask = null;
this.containerClassLoader = null;
| public void | destroyObject(java.lang.Object object)Destroys an Object. Note that applications should not ignore
the reference to the object that they got from getObject(). An object
that is obtained through getObject() must always be returned back to
the pool using either returnObject(obj) or through destroyObject(obj).
This method tells that the object should be destroyed and cannot
be reused.
synchronized (list) {
destroyedCount++;
}
try {
factory.destroy(object);
} catch (Exception ex) {
_logger.log(Level.FINE, "exception in destroyObject", ex);
}
| protected void | doResize()
//We need to set the context class loader for this (deamon) thread!!
final Thread currentThread = Thread.currentThread();
final ClassLoader previousClassLoader =
currentThread.getContextClassLoader();
final ClassLoader ctxClassLoader = containerClassLoader;
long startTime = 0;
boolean enteredResizeBlock = false;
try {
if(System.getSecurityManager() == null) {
currentThread.setContextClassLoader(ctxClassLoader);
} else {
java.security.AccessController.doPrivileged(
new java.security.PrivilegedAction() {
public java.lang.Object run() {
currentThread.setContextClassLoader(ctxClassLoader);
return null;
}
});
}
if(_logger.isLoggable(Level.FINE)) {
_logger.log(Level.FINE,
"[Pool-"+poolName+"]: Resize started at: "
+ (new java.util.Date())+" steadyPoolSize ::"+steadyPoolSize
+ " resizeQuantity ::"+resizeQuantity+" maxPoolSize ::" +
maxPoolSize );
}
startTime = System.currentTimeMillis();
ArrayList removeList = new ArrayList();
int populateCount = 0;
synchronized (list) {
if (inResizing == true) {
return;
}
enteredResizeBlock = true;
inResizing = true;
int curSize = list.size();
if (curSize > steadyPoolSize) {
//possible to reduce pool size....
if ((idleTimeoutInSeconds <= 0) ||
(resizeQuantity <= 0)) {
return;
}
int victimCount =
(curSize > (steadyPoolSize + resizeQuantity) )
? resizeQuantity : (curSize - steadyPoolSize);
long allowedIdleTime = System.currentTimeMillis() -
idleTimeoutInSeconds*1000;
if(_logger.isLoggable(Level.FINE)) {
_logger.log(Level.FINE,
"[Pool-"+poolName+"]: Resize:: reducing "
+ " pool size by: " + victimCount);
}
for (int i=0; i<victimCount; i++) {
//removeList.add(list.remove(--curSize));
//destroyedCount++;
EJBContextImpl ctx = (EJBContextImpl) list.get(0);
if (ctx.getLastTimeUsed() <= allowedIdleTime) {
removeList.add(list.remove(0));
destroyedCount++;
} else {
break;
}
}
} else if (curSize < steadyPoolSize) {
//Need to populate....
if (maintainSteadySize == false) {
return;
}
if (resizeQuantity <= 0) {
populateCount = steadyPoolSize - curSize;
} else {
while ((curSize + populateCount) < steadyPoolSize) {
populateCount += resizeQuantity;
}
if ((curSize + populateCount) > maxPoolSize) {
populateCount -= (curSize + populateCount) - maxPoolSize;
}
}
}
}
if (removeList.size() > 0) {
int sz = removeList.size();
for (int i=0; i<sz; i++) {
try {
factory.destroy(removeList.get(i));
} catch (Throwable th) {
_logger.log(Level.FINE, "exception in doResize", th);
}
}
}
if (populateCount > 0) {
//preload adds items inside a sync block....
if(_logger.isLoggable(Level.FINE)) {
_logger.log(Level.FINE,
"[Pool-"+poolName+"]: Attempting to preload "
+ populateCount + " beans. CurSize/MaxPoolSize: "
+ list.size() + "/" + maxPoolSize);
}
preload(populateCount);
if(_logger.isLoggable(Level.FINE)) {
_logger.log(Level.FINE,
"[Pool-"+poolName+"]: After preload "
+ "CurSize/MaxPoolSize: "
+ list.size() + "/" + maxPoolSize);
}
}
} catch (Throwable th) {
_logger.log(Level.WARNING,
"[Pool-"+poolName+"]: Exception during reSize", th);
} finally {
if (enteredResizeBlock) {
synchronized (list) {
inResizing = false;
}
}
if(System.getSecurityManager() == null) {
currentThread.setContextClassLoader(previousClassLoader);
} else {
java.security.AccessController.doPrivileged(
new java.security.PrivilegedAction() {
public java.lang.Object run() {
currentThread.setContextClassLoader(previousClassLoader);
return null;
}
});
}
}
long endTime = System.currentTimeMillis();
if(_logger.isLoggable(Level.FINE)) {
_logger.log(Level.FINE,
"[Pool-"+poolName+"]: Resize completed at: "
+ (new java.util.Date()) + "; after reSize: " +
getAllAttrValues());
_logger.log(Level.FINE, "[Pool-"+poolName+"]: Resize took: "
+ ((endTime-startTime)/1000.0) + " seconds.");
}
| public java.lang.String | getAllAttrValues()
StringBuffer sbuf = new StringBuffer("[Pool-"+poolName+"] ");
sbuf.append("CC=").append(createdCount).append("; ")
.append("DC=").append(destroyedCount).append("; ")
.append("CS=").append(list.size()).append("; ")
.append("SS=").append(steadyPoolSize).append("; ")
.append("MS=").append(maxPoolSize).append(";");
return sbuf.toString();
| public java.lang.Object | getObject(boolean canWait, java.lang.Object param)Get an object. Application can use pool.getObject() to get an object
instead of using new XXX().
return getObject(param);
| public java.lang.Object | getObject(long maxWaitTime, java.lang.Object param)
return getObject(param);
| public java.lang.Object | getObject(java.lang.Object param)
boolean toAddResizeTask = false;
Object obj = null;
synchronized (list) {
int size = list.size();
if (size > steadyPoolSize) {
poolSuccess++;
return list.remove(size-1);
} else if (size > 0) {
poolSuccess++;
if ((maintainSteadySize) && (addedResizeTask == false)) {
toAddResizeTask = addedResizeTask = true;
obj = list.remove(size-1);
} else {
return list.remove(size-1);
}
} else {
if ((maintainSteadySize) && (addedResizeTask == false)) {
toAddResizeTask = addedResizeTask = true;
}
createdCount++; //hope that everything will be OK.
}
}
if (toAddResizeTask) {
addResizeTaskForImmediateExecution();
}
if (obj != null) {
return obj;
}
try {
return factory.create(param);
} catch (RuntimeException th) {
synchronized (list) {
createdCount--;
}
throw th;
}
| protected void | initializePool(ObjectFactory factory, int steadyPoolSize, int resizeQuantity, int maxPoolSize, int idleTimeoutInSeconds, java.lang.ClassLoader loader)
list = new ArrayList();
this.factory = factory;
this.steadyPoolSize = (steadyPoolSize <= 0) ? 0 : steadyPoolSize;
this.resizeQuantity = (resizeQuantity <= 0) ? 0 : resizeQuantity;
this.maxPoolSize = (maxPoolSize <= 0)
? Integer.MAX_VALUE : maxPoolSize;
this.steadyPoolSize = (this.steadyPoolSize > this.maxPoolSize)
? this.maxPoolSize : this.steadyPoolSize;
this.idleTimeoutInSeconds =
(idleTimeoutInSeconds <= 0) ? 0 : idleTimeoutInSeconds;
this.containerClassLoader = loader;
this.maintainSteadySize = (this.steadyPoolSize > 0);
if ((this.idleTimeoutInSeconds > 0) && (this.resizeQuantity > 0)) {
try {
this.poolTimerTask = new PoolResizeTimerTask();
ContainerFactoryImpl.getTimer().scheduleAtFixedRate
(poolTimerTask, idleTimeoutInSeconds*1000,
idleTimeoutInSeconds*1000);
if(_logger.isLoggable(Level.FINE)) {
_logger.log(Level.FINE,
"[Pool-" + poolName + "]: Added PoolResizeTimerTask...");
}
} catch (Throwable th) {
_logger.log(Level.WARNING,"[Pool-" +
poolName + "]: Could not add"
+ " PoolTimerTask. Continuing anyway...", th);
}
}
| protected void | preload(int count)Preload the pool with objects.
ArrayList instances = new ArrayList(count);
try {
for (int i=0; i<count; i++) {
instances.add(factory.create(null));
}
} catch (Exception ex) {
//Need not throw this exception up since we are pre-populating
}
int sz = instances.size();
if (sz == 0) {
return;
}
synchronized (list) {
for (int i=0; i<sz; i++) {
list.add(instances.get(i));
}
createdCount += sz;
}
| public void | prepopulate(int count)Prepopulate the pool with objects.
this.steadyPoolSize = (count <= 0) ? 0 : count;
this.steadyPoolSize = (this.steadyPoolSize > this.maxPoolSize)
? this.maxPoolSize : this.steadyPoolSize;
if (this.steadyPoolSize > 0) {
preload(this.steadyPoolSize);
}
| protected void | remove(int count)
ArrayList removeList = new ArrayList();
synchronized (list) {
int size = list.size();
for (int i=0; (i<count) && (size > 0); i++) {
removeList.add(list.remove(--size));
destroyedCount++;
}
}
int sz = removeList.size();
for (int i=0; i<sz; i++) {
try {
factory.destroy(removeList.get(i));
} catch (Throwable th) {
_logger.log(Level.FINE, "exception in remove", th);
}
}
| protected void | removeIdleObjects()
| public void | returnObject(java.lang.Object object)Return an object back to the pool. An object that is obtained through
getObject() must always be returned back to the pool using either
returnObject(obj) or through destroyObject(obj).
synchronized (list) {
if (list.size() < maxPoolSize) {
list.add(object);
return;
} else {
destroyedCount++;
}
}
try {
factory.destroy(object);
} catch (Exception ex) {
_logger.log(Level.FINE, "exception in returnObj", ex);
}
| public void | setContainerClassLoader(java.lang.ClassLoader loader)
this.containerClassLoader = loader;
|
|