⭐ 欢迎来到虫虫下载站! | 📦 资源下载 📁 资源专辑 ℹ️ 关于我们
⭐ 虫虫下载站

📄 objectpool.java

📁 java编写的数据库连接池的源代码。包含有连接池的源码。
💻 JAVA
📖 第 1 页 / 共 2 页
字号:
/*
	DBPool - JDBC Connection Pool Manager
	Copyright (c) Giles Winstanley
*/
package snaq.util;

import java.io.*;
import java.text.*;
import java.util.*;

/**
 * Base class for a pool system implementation.
 * This class provides all the base functionality required and can be easily
 * extended to provide pooling support for many different types of object.
 * <p>New objects are retrieved on demand according to specified limits,
 * and the pool can also ensure an object's validity before returning it.
 * The limits which can be set for a pool include the number of items to be
 * held in the pool, and the maximum number to ever be created.
 * <p>The pool will try to maintain <tt>poolSize</tt> items open and ready
 * for use (unless that number has not yet been created), but if expiry is
 * enabled this number will reduce if the items are not used frequently.
 * If <tt>maxSize</tt> is specified then the pool will never create more
 * than this number of items, and another can only be obtained from the pool
 * if it is handed back by another client.
 * <p><tt>ObjectPool</tt> should be sub-classed to override
 * the following methods:</p>
 * <pre>
 *   protected Reusable create() throws Exception
 *   protected boolean isValid(final Reusable o)
 *   protected void destroy(final Reusable o)
 * </pre>
 * <p>It is recommended that the sub-class implements methods for obtaining
 * and returning items within the pool, casting the objects returned by this
 * class as required to the appropriate class type.
 * <p>ObjectPool also support asynchronous destruction of items, which can be
 * useful in circumstances where destruction of items held can take a long
 * time which would delay the <tt>checkIn</tt> method. This also applies
 * to the release of the pool after it's final use, which should always be
 * done using either <tt>release</tt> or <tt>releaseAsync</tt>.
 * @author Giles Winstanley
 */
public abstract class ObjectPool extends LogUtil
{
	private String name;
	private List free, used;
	private int poolSize, maxSize;
	private long expiryTime;
	private long requests, hits;
	private boolean released = false;
	private boolean asyncDestroy = false;
	private DateFormat dateFormat;
	private Cleaner cleaner;
	private static int cleanerCount = 0;
	private List listeners = new ArrayList();


	/**
	 * Creates new object pool.
	 * @param name pool name
	 * @param poolSize maximum number of pooled objects, or 0 for no limit
	 * @param maxSize maximum number of possible objects, or 0 for no limit
	 * @param expiryTime expiry time (milliseconds) for pooled object, or 0 for no expiry
	 */
	protected ObjectPool(String name, int poolSize, int maxSize, long expiryTime)
	{
		Class type = getPoolClass();
		if (!List.class.isAssignableFrom(type))
			throw new RuntimeException("Invalid pool class type specified: " + type.getName() + " (must implement List)");
		try
		{
			free = (List)type.newInstance();
			used = (List)type.newInstance();
		}
		catch (Exception e)
		{
			throw new RuntimeException("Unable to instantiate pool class type: " + type.getName());
		}
		this.name = name;
		this.setParameters(poolSize, maxSize, expiryTime);
	}

	/**
	 * Creates new object pool.
	 * @param name pool name
	 * @param poolSize maximum number of pooled objects, or 0 for no limit
	 * @param maxSize maximum number of possible objects, or 0 for no limit
	 * @param expiryTime expiry time (milliseconds) for pooled object, or 0 for no expiry
	 */
	protected ObjectPool(String name, int poolSize, int maxSize, int expiryTime)
	{
		this(name, poolSize, maxSize, (long)expiryTime);
	}


	/**
	 * Checks out an item from the pool. If no free item
	 * is available, a new item is created unless the maximum
	 * number of items has been reached. If a free item
	 * is not valid it is removed from the pool and another
	 * is retrieved.
	 * @return item from the pool, or null if nothing available
	 * @exception Exception if there is an error creating a new object
	 */
	protected final synchronized Reusable checkOut() throws Exception
	{
		if (released)
			throw new RuntimeException("Pool no longer valid for use");
		int oldTotalConns = used.size() + free.size();

		TimeWrapper tw = null;
		Reusable o = null;
		if (free.size() > 0)
		{
			//  Get an object from the free list
			tw = (TimeWrapper)free.remove(0);
			o = (Reusable)tw.getObject();
			boolean valid = isValid(o);
			while (!valid  &&  free.size() > 0)
			{
				destroyObject(o);
				log("Removed invalid item from pool");
				tw = (TimeWrapper)free.remove(free.size() - 1);
				o = (Reusable)tw.getObject();
				valid = isValid(o);
			}
			if (free.size() == 0  &&  !valid)
				o = null;
		}
		boolean hit = (o != null);

		// If no free connections and can create more...create new one
		if (o == null)
		{
			if (maxSize > 0  &&  used.size() == maxSize)
				fireMaxSizeLimitErrorEvent();
			else if (used.size() < maxSize  ||  maxSize == 0)
			{
				o = create();
				if (!isValid(o))
					throw new RuntimeException("Unable to create a valid connection");
			}
		}
		
		// If a connection has been obtained/created, add it to used items collection
		if (o != null)
		{
			used.add(o);
			requests++;
			if (hit)
				hits++;
			firePoolCheckOutEvent();
			// Check for limit reaching so events can be fired.
			// (Events only fired on increase of connection numbers).
			int totalConns = used.size() + free.size();
			if (totalConns == poolSize  &&  totalConns > oldTotalConns)
				fireMaxPoolLimitReachedEvent();
			else if (totalConns == poolSize + 1  &&  totalConns > oldTotalConns)
				fireMaxPoolLimitExceededEvent();
			if (totalConns == maxSize  &&  totalConns > oldTotalConns)
				fireMaxSizeLimitReachedEvent();
		}
		if (debug)
		{
			String ratio = used.size() + "/" + (used.size() + free.size());
			String hitRate = " (HitRate=" + getHitRate() + "%)";
			log("Checkout - " + ratio + hitRate + (o == null ? " - null returned" : ""));
		}
		return o;
	}


	/**
	 * Checks out an item from the pool.
	 * If there is no pooled item available and the maximum number
	 * possible has not been reached, another is created.
	 * If a free item is detected as being invalid it is removed
	 * from the pool and the another is retrieved.
	 * If an item is not available and the maximum number possible
	 * has been reached, the method waits for the timeout period
	 * for one to become available by being checked in.
	 * @param timeout timeout value in milliseconds
	 * @return item from the pool, or null if nothing available within timeout period
	 * @exception Exception if there is an error creating a new object
	 */
	protected final synchronized Reusable checkOut(long timeout) throws Exception
	{
		long time = System.currentTimeMillis();
		Reusable o = null;
		o = checkOut();
		while (o == null  &&  (System.currentTimeMillis() - time < timeout))
		{
			try
			{
				if (debug)
					log("No pooled items spare...waiting for up to " + timeout + "ms");
				wait(timeout);
				o = checkOut();
			}
			catch (InterruptedException e) { log(e, "Connection checkout interrupted"); }
		}
		return o;
	}


	/**
	 * Checks an object into the pool, and notify other
	 * threads that may be waiting for one.
	 * @param o object to check in
	 */
	protected final void checkIn(Reusable o)
	{
		if (o == null)
		{
			log("Attempt to return null item");
			return;
		}
		
		synchronized(this)
		{
			firePoolCheckInEvent();
			
			// Check if item is from this pool
			if (!used.remove(o))
			{
				log("Attempt to return item not belonging to pool");
				throw new RuntimeException("Attempt to return item not belonging to pool " + name);
			}

			// If pool is full destroy object, else place in pool
			boolean kill = maxSize > 0  &&  (free.size() + used.size() >= poolSize);
			kill = kill  ||  (maxSize == 0  &&  free.size() >= poolSize);
			if (kill)
			{
				destroyObject(o);
				if (debug)
					log("Checkin* - " + used.size() + "/" + (used.size()+free.size()));
			}
			else
			{
				try
				{
					//  Recycle object for next use
					o.recycle();
					//  Add object to free list
					free.add(new TimeWrapper(null, o, expiryTime));
					if (debug)
						log("Checkin  - " + used.size() + "/" + (used.size()+free.size()));
					notifyAll();
				}
				catch (Exception e)
				{
					// If unable to recycle object, destroy it
					destroyObject(o);
					log("Unable to recycle item - destroyed");
				}
			}
		}
	}


	/**
	 * Releases all items from the pool, and shuts the pool down.
	 * If any items are still checked-out, this method waits until all items have
	 * been checked-in before returning.
	 */
	public final void release() { release(false); }

	/**
	 * Releases all items from the pool, and shuts the pool down.
	 * This method returns immediately; a background thread is created to perform the release.
	 */
	public final synchronized void releaseAsync() { releaseAsync(false); }

	/**
	 * Forcibly releases all items from the pool, and shuts the pool down.
	 * If any items are still checked-out, this method forcibly destroys them
	 * and then returns.
	 */
	public final void releaseForcibly() { release(true); }

	/**
	 * Releases all items from the pool, and shuts the pool down.
	 * @param forced whether to forcibly destroy items, or let them be checked-in
	 */
	private final void release(boolean forced)
	{
		// Set released flag to prevent check-out of new items
		if (released)
			return;
		released = true;
		//  Destroy cleaner thread
		if (cleaner != null)
		{
			cleaner.halt();
			try { cleaner.join(); }
			catch (InterruptedException ie) { ie.printStackTrace(); }
			cleaner = null;
		}

		synchronized(this)
		{
			int rel = 0, failed = 0;
			TimeWrapper tw = null;
			Reusable o = null;
			// Destroy all items still in use
			if (forced)
			{
				Iterator iter = used.iterator();
				while (iter.hasNext())
				{
					o = (Reusable)iter.next();
					try
					{
						destroy(o);
						rel++;
					}
					catch (Exception ex)
					{
						failed++;
						log(ex, "Unable to release item in pool");
					}
				}
				used.clear();
			}
			else
			{
				if (debug  &&  used.size() > 0)
					log("Waiting for used items to be checked-in...");
				while (used.size() > 0)
				{
					try { wait(); }
					catch (InterruptedException e) {}
				}
			}

			// Destroy all currently free items
			Iterator iter = free.iterator();
			while (iter.hasNext())
			{
				tw = (TimeWrapper)iter.next();
				o = (Reusable)tw.getObject();
				try
				{
					destroy(o);
					rel++;
				}
				catch (Exception ex)
				{
					failed++;
					log(ex, "Unable to release item in pool");
				}
			}
			free.clear();

			//  Destroy log reference
			if (debug)
			{
				String s = "Released " + rel + (rel > 1 ? " items" : " item");
				if (failed > 0)
					s += " (failed to release " + failed + (failed > 1 ? " items)" : " item)");
				log(s);
			}
			firePoolReleasedEvent();
			listeners.clear();
			super.close();
		}
	}

	/**
	 * Releases all items from the pool, and shuts the pool down.
	 * This method returns immediately; a background thread is created to perform the release.
	 */
	private final void releaseAsync(final boolean forced)
	{
		Thread t = new Thread(new Runnable()
		{
			public void run() { release(forced); }
		});
		t.start();
	}


	/**

⌨️ 快捷键说明

复制代码 Ctrl + C
搜索代码 Ctrl + F
全屏模式 F11
切换主题 Ctrl + Shift + D
显示快捷键 ?
增大字号 Ctrl + =
减小字号 Ctrl + -