📄 objectpool.java
字号:
* Object creation method.
* This method is called when a new item needs to be created following a call
* to one of the check-out methods.
* @exception Exception if unable to create the item
*/
protected abstract Reusable create() throws Exception;
/**
* Object validation method.
* This method is called when checking-out an item to see if it is valid for use.
* When overridden by the sub-class it is recommended that this method perform
* suitable checks to ensure the object can be used without problems.
*/
protected abstract boolean isValid(final Reusable o);
/**
* Object destruction method.
* This method is called when an object needs to be destroyed due to pool
* pruning/cleaning, or final release of the pool.
*/
protected abstract void destroy(final Reusable o);
/**
* Destroys the given object (asynchronously if necessary).
*/
private final void destroyObject(final Reusable o)
{
if (o == null)
return;
if (asyncDestroy)
{
Thread t = new Thread(new Runnable()
{
public void run() { destroy(o); }
});
t.start();
}
else
destroy(o);
}
/**
* Determines whether to perform asynchronous object destruction.
* If set to true then each time an object is destroyed (invalid object
* during pool operation, or when the pool is finally released) the operation
* is done in a separate thread, allowing the method to return immediately.
* This can be useful when calling the destroy method on an object takes a
* long time to complete.
*/
public final void setAsyncDestroy(boolean b) { asyncDestroy = b; }
/**
* Returns whether asynchronous object destruction is enabled.
* (Default: false)
*/
public final boolean isAsyncDestroy() { return asyncDestroy; }
/**
* Writes a message to the log.
*/
public void log(String logEntry)
{
log(name + ": ", logEntry);
}
/**
* Writes a message with an Exception to the log file.
*/
public void log(Throwable e, String logEntry)
{
log(e, name + ": ", logEntry);
}
/**
* Returns the pool name.
*/
public final String getName() { return this.name; }
/**
* Returns the maximum size of the pool.
*/
public final int getPoolSize() { return poolSize; }
/**
* Returns the maximum number of items that can be created.
*/
public final int getMaxSize() { return maxSize; }
/**
* Returns the expiry time for unused items in the pool.
*/
public final long getExpiryTime() { return expiryTime; }
/**
* Sets the pooling parameters.
* Any items currently in the pool will remain, subject to the new parameters.
* (The hit rate counters are reset when this method is called.)
* @param poolSize number of items to be keep in pool
* @param maxSize maximum number of items to be created
* @param expiryTime expiry time for unused items (milliseconds) (0 = no expiry)
*/
public final void setParameters(int poolSize, int maxSize, long expiryTime)
{
synchronized(this)
{
if (cleaner != null)
cleaner.halt();
this.poolSize = Math.max(poolSize, 0);
this.maxSize = Math.max(maxSize, 0);
this.expiryTime = Math.max(expiryTime, 0);
if (this.maxSize > 0 && this.maxSize < this.poolSize)
this.maxSize = this.poolSize;
resetHitCounter();
// Update pooled items to use new expiry
Iterator iter = free.iterator();
TimeWrapper tw = null;
while (iter.hasNext())
{
tw = (TimeWrapper)iter.next();
tw.setLiveTime(expiryTime);
}
// Creates cleaner thread with check interval of at most 5 seconds.
if (this.expiryTime > 0)
{
long iVal = Math.min(5000, this.expiryTime / 5);
(cleaner = new Cleaner(this, iVal)).start();
}
}
if (debug)
{
String info = "pool=" + this.poolSize + ",max=" + this.maxSize + ",expiry=";
info += this.expiryTime == 0 ? "none" : this.expiryTime + "ms";
log("Parameters changed (" + info + ")");
}
if (listeners != null)
fireParametersChangedEvent();
}
/**
* Returns the total number of objects held (available and checked-out).
*/
public final synchronized int getSize() { return free.size() + used.size(); }
/**
* Returns the number of items that are currently checked-out.
*/
public final synchronized int getCheckedOut() { return used.size(); }
/**
* Returns the number of items held in the pool that are free to be checked-out.
*/
public final synchronized int getFreeCount() { return free.size(); }
/**
* Returns hit rate of the pool as a percentage.
* The hit rate is the proportion of requests for a connection which result
* in the return of a connection which is in the pool, rather than which
* results in the creation of a new connection.
*/
public final float getHitRate() { return (requests == 0) ? 0 : (((float)hits / requests) * 100f); }
/**
* Resets the counter for determining the pool's hit rate.
*/
protected final void resetHitCounter() { requests = hits = 0; }
/**
* Returns the class to use for the pool collection.
* This can be over-ridden by a sub-class to provide a different List
* type for the pool, which may give performance benefits in certain situations.
* Only instances of List collections should be used.
* (Default: java.util.ArrayList.class)
* For those wanting to override this method, pool items are checked-out from
* the front of the List - <tt>remove(0)</tt> - and replaced at the end of
* the List when checked-in again - <tt>add(Object)</tt>.
*/
protected Class getPoolClass() { return ArrayList.class; }
/**
* Shuts down the object pool.
* If overridden the sub-class should make sure super.finalize() is called.
*/
public void finalize()
{
if (cleaner != null)
{
cleaner.halt();
cleaner = null;
}
}
/**
* Flushes the pool of all currently available items.
*/
public final void flush()
{
int count = 0;
synchronized(this)
{
Iterator iter = free.iterator();
TimeWrapper tw = null;
while (iter.hasNext())
{
tw = (TimeWrapper)iter.next();
iter.remove();
destroyObject((Reusable)tw.getObject());
count++;
}
}
if (count > 0 && debug)
log("Flushed all spare items from pool");
}
/**
* Purges expired objects from the pool.
* This method is called by the cleaner thread to purge expired items.
* @return false if pool is empty after purging (no further purge required until items added), true otherwise
*/
final synchronized boolean purge()
{
if (debug)
log("Checking for expired items");
int count = 0;
Iterator iter = free.iterator();
TimeWrapper tw = null;
while (iter.hasNext())
{
tw = (TimeWrapper)iter.next();
if (tw.isExpired())
{
iter.remove();
destroyObject((Reusable)tw.getObject());
count++;
}
}
return free.size() > 0 || count > 0;
}
//**************************
// Event-handling methods
//**************************
/**
* Adds an ObjectPoolListener to the event notification list.
*/
public final void addObjectPoolListener(ObjectPoolListener x)
{
listeners.add(x);
}
/**
* Removes an ObjectPoolListener from the event notification list.
*/
public final void removeObjectPoolListener(ObjectPoolListener x)
{
listeners.remove(x);
}
private final void firePoolCheckOutEvent()
{
ObjectPoolEvent poolEvent = new ObjectPoolEvent(this, ObjectPoolEvent.CHECKOUT);
for (Iterator iter = listeners.iterator(); iter.hasNext();)
((ObjectPoolListener)iter.next()).poolCheckOut(poolEvent);
}
private final void firePoolCheckInEvent()
{
ObjectPoolEvent poolEvent = new ObjectPoolEvent(this, ObjectPoolEvent.CHECKIN);
for (Iterator iter = listeners.iterator(); iter.hasNext();)
((ObjectPoolListener)iter.next()).poolCheckIn(poolEvent);
}
private final void fireMaxPoolLimitReachedEvent()
{
ObjectPoolEvent poolEvent = new ObjectPoolEvent(this, ObjectPoolEvent.MAX_POOL_LIMIT_REACHED);
for (Iterator iter = listeners.iterator(); iter.hasNext();)
((ObjectPoolListener)iter.next()).maxPoolLimitReached(poolEvent);
}
private final void fireMaxPoolLimitExceededEvent()
{
ObjectPoolEvent poolEvent = new ObjectPoolEvent(this, ObjectPoolEvent.MAX_POOL_LIMIT_EXCEEDED);
for (Iterator iter = listeners.iterator(); iter.hasNext();)
((ObjectPoolListener)iter.next()).maxPoolLimitExceeded(poolEvent);
}
private final void fireMaxSizeLimitReachedEvent()
{
ObjectPoolEvent poolEvent = new ObjectPoolEvent(this, ObjectPoolEvent.MAX_SIZE_LIMIT_REACHED);
for (Iterator iter = listeners.iterator(); iter.hasNext();)
((ObjectPoolListener)iter.next()).maxSizeLimitReached(poolEvent);
}
private final void fireMaxSizeLimitErrorEvent()
{
ObjectPoolEvent poolEvent = new ObjectPoolEvent(this, ObjectPoolEvent.MAX_SIZE_LIMIT_ERROR);
for (Iterator iter = listeners.iterator(); iter.hasNext();)
((ObjectPoolListener)iter.next()).maxSizeLimitError(poolEvent);
}
private final void fireParametersChangedEvent()
{
ObjectPoolEvent poolEvent = new ObjectPoolEvent(this, ObjectPoolEvent.PARAMETERS_CHANGED);
for (Iterator iter = listeners.iterator(); iter.hasNext();)
((ObjectPoolListener)iter.next()).poolParametersChanged(poolEvent);
}
private final void firePoolReleasedEvent()
{
ObjectPoolEvent poolEvent = new ObjectPoolEvent(this, ObjectPoolEvent.POOL_RELEASED);
for (Iterator iter = listeners.iterator(); iter.hasNext();)
((ObjectPoolListener)iter.next()).poolReleased(poolEvent);
}
/**
* Thread to perform clean-up of expired objects in pool.
* Each time nothing is cleaned because the pool is empty the cleaner waits
* until an item is returned, when it is woken up and starts cleaning again.
*/
final class Cleaner extends Thread
{
private ObjectPool pool;
private long interval;
private boolean stopped;
Cleaner(ObjectPool pool, long interval)
{
this.setName("CleanerThread" + Integer.toString(cleanerCount++));
this.pool = pool;
this.interval = interval;
}
public void start()
{
stopped = false;
super.start();
}
/**
* Safely stops the thread from running.
*/
public void halt()
{
if (!isHalted())
{
stopped = true;
interrupt(); // Wake cleaner if necessary
}
}
/**
* Returns whether the thread has been halted.
*/
public boolean isHalted() { return stopped; }
/**
* Handles the expiry of old objects.
*/
public void run()
{
while (pool.cleaner == Thread.currentThread() && !stopped)
{
synchronized(pool)
{
if (!pool.purge())
{
try { pool.wait(); }
catch (InterruptedException e) {}
}
}
if (!stopped)
{
try { sleep(interval); }
catch (InterruptedException e) {}
}
}
}
}
}
⌨️ 快捷键说明
复制代码
Ctrl + C
搜索代码
Ctrl + F
全屏模式
F11
切换主题
Ctrl + Shift + D
显示快捷键
?
增大字号
Ctrl + =
减小字号
Ctrl + -