关于多线程和对象池化的使用,最近写了一个对象池和一个多线程测试程序, 不过输出结果不是很令人满意, 所以在此想请各位指点一二看看我的程序哪里有问题. 谢谢~~

黑菜妞妞 发布于 2011/08/16 15:54
阅读 1K+
收藏 1
/**
 * 对象池工厂
 * @author li.hw
 *
 */
public class ObjectPoolFactory {
	
	private static ObjectPoolFactory objectPoolFactory;		//singleton
	
	/**
	 * 
	 */
	private ObjectPoolFactory(){
		super();
	}
	
	/**
	 * 
	 * @return
	 */
	public static ObjectPoolFactory getInstance(){
		
		if(objectPoolFactory==null){
			return new ObjectPoolFactory();
		}
		return objectPoolFactory;
	}
	
	/**
	 * 
	 * @param paramObj
	 * @param classType
	 * @return
	 */
	public ObjectPool createPool(ParameterObject paramObj, Class classType){
		return new ObjectPool(paramObj, classType);
	}
	
	/**
	 * 
	 * @param objectPool
	 */
	public void destroyPool(ObjectPool objectPool){
		objectPool = null;
	}
}
/**
 * 对象池
 * @author li.hw
 *
 */
public class ObjectPool {
	
	private ParameterObject paramObj;	//该对象池的属性参数对象
	private Class classType;			//该对象池中所存放对象的类型
	private Object currentObj;			//该对象池当前可以借出的对象
	private Vector pool;				//用于存放对象的池, Vector是一个stack, 所以pool是一个对象栈池
	
	/**
	 * 
	 * @param paramObj
	 * @param classType
	 */
	public ObjectPool(ParameterObject paramObj, Class classType) {

		//ObjectPool利用一个java.util.Vector作为可扩展的对象池,
		//并通过它的构造函数来指定池化对象的 Class类型及对象池的一些属性
		this.paramObj = paramObj;
		this.classType = classType;
		pool = new Vector();

		//创建所有对象并放进pool中
		for(int i=0;i<this.paramObj.getMaxCount();i++){
			PoolableObjectFactory objFactory = PoolableObjectFactory.getInstance();
			pool.add(objFactory.createObject(classType));
		}
	}
	
	
	/**
	 * 
	 * @return
	 */
	public Object borrowObject() {
		
		if(pool.size()>0){
			
			System.out.println("pool中有可用的对象" + pool.size() + "个");
			//如果pool中有可用的对象就返回pool栈中第一个可用的对象
			currentObj = pool.firstElement();
			
			//删除pool中刚借出的对象,注意removeElementAt(0)只是删除pool中指向该对象的引用,该对象在内存中还是存在的
			pool.removeElementAt(0);
			return currentObj;
		} else {
			System.out.println("pool中没有可用的对象, 请耐心等待");
			//如果当前池中无对象可用,就只能等待其它线程返回对象到池中
			synchronized(this) {
				try {
					wait();
				} catch (InterruptedException e) {
					System.out.println(e.getMessage());
					e.printStackTrace();
				}
				currentObj = pool.firstElement();
				pool.removeElementAt(0);
				return currentObj;
			}
		}		
	}
	
	
	/**
	 * 当return一个对象时, pool就会追加该对象
	 * @param obj
	 */
	public void returnObject(Object obj) {
		// 确保对象具有正确的类型
		//TODO: 因为obj是之前对象栈池的第一个元素, 如果该对象是有状态的需要考虑是否还原到对象的初始状态
		//例如: obj是一个BufferString, 在之前的一次使用中append了一个字串"hello", 当return到pool中的
		//时候就要清楚该"hello"字串, 否则当该对象下一次被借出并append新的字串时会包含上一次使用时append
		//的"hello"字串
		((StringBuffer)obj).delete(0, ((StringBuffer)obj).length());	//恢复对象初始状态
		pool.addElement(obj);	//把使用完的对象放回pool中
		synchronized (this) {
			notifyAll();
		}
	}
}
/**
 * 对象池参数
 * @author li.hw
 *
 */
public class ParameterObject {
	
	private int maxCount;
	private int minCount;
	
	/**
	 * 
	 * @param maxCount
	 * @param minCount
	 */
	public ParameterObject(int maxCount, int minCount){
		this.maxCount = maxCount;
		this.minCount = minCount;
	}
		
	public int getMaxCount() {
		return maxCount;
	}
	public void setMaxCount(int maxCount) {
		this.maxCount = maxCount;
	}
	public int getMinCount() {
		return minCount;
	}
	public void setMinCount(int minCount) {
		this.minCount = minCount;
	}
}
/**
 * 对象池化工厂
 * @author li.hw
 *
 */
public class PoolableObjectFactory {
	
	private static PoolableObjectFactory poolableObjectFactory;		//singleton
	
	/**
	 * 
	 */
	private PoolableObjectFactory(){
		super();
	}
	
	/**
	 * 
	 * @return
	 */
	public static PoolableObjectFactory getInstance(){
		
		if(poolableObjectFactory==null){
			return new PoolableObjectFactory();
		}
		return poolableObjectFactory;
	}
	
	/**
	 * 
	 * @param classType
	 * @return
	 * @throws InstantiationException
	 * @throws IllegalAccessException
	 */
	public Object createObject(Class classType) {
		Object obj = null;
		try {
			obj = classType.newInstance();
		} catch (InstantiationException e) {
			
		} catch (IllegalAccessException e) {
			throw new IllegalArgumentException("classType参数错误");
		}
		return obj;
	}
	
	//TODO: 从内存中删除该对象
	public void destroyObject(Object obj){
		obj = null;
	}

}
/**
 * 通用对象池的演示
 * @author li.hw
 *
 */
public class TestGeneralObjectPool implements Runnable  {
	
	private static ObjectPool pool;
	
	/**
	 * @param args
	 */
	public static void main(String[] args) {
		
		System.out.println("创建对象池");
		//创建对象池工厂
		ObjectPoolFactory poolFactory = ObjectPoolFactory. getInstance ();
		
		//定义所创建对象池的属性
		ParameterObject paraObj = new ParameterObject(1,1);
		
		//利用对象池工厂,创建一个存放StringBuffer类型对象的对象池
		pool = poolFactory.createPool(paraObj,StringBuffer.class);
		//TODO: this pool should be stored in cache for further use
		
		//编写几个独立的线程去借出使用并归还对象
	    System.out.println(Thread.currentThread().getName() + " 线程运行开始!");
	    TestGeneralObjectPool test = new TestGeneralObjectPool();
	    Thread thread1 = new Thread(test);
	    Thread thread2 = new Thread(test);
	    Thread thread3 = new Thread(test);
	    thread1.start();
	    thread2.start();
	    thread3.start();
	    System.out.println(Thread.currentThread().getName() + " 线程运行结束!");
		}
	
	public void run() {
	    System.out.println(Thread.currentThread().getName() + " 线程运行开始!");
	    for (int i = 0; i < 10; i++) {
	    	 System.out.println(Thread.currentThread().getName() + "尝试借出对象");
	        StringBuffer buffer = (StringBuffer)pool.borrowObject();
	        buffer.append(Thread.currentThread().getName() + ", " + String.valueOf(i));
	        System.out.println(buffer.toString());
	        
	        //等待5秒然后再归还该对象到pool
	        try {
	        	Thread.sleep(5000);
	        } catch (InterruptedException e) {
	            e.printStackTrace();
	        }
	        pool.returnObject(buffer);	        
	    }
	    System.out.println(Thread.currentThread().getName() + " 线程运行结束!");
	}
}



下面是输出的结果

创建对象池
main 线程运行开始!
Thread-0 线程运行开始!
main 线程运行结束!
Thread-0尝试借出对象
pool中有可用的对象1个
Thread-2 线程运行开始!
Thread-0, 0
Thread-2尝试借出对象
Thread-1 线程运行开始!
pool中没有可用的对象, 请耐心等待
Thread-1尝试借出对象
pool中没有可用的对象, 请耐心等待
Thread-0尝试借出对象
pool中有可用的对象1个
Thread-0, 1
Exception in thread "Thread-1" java.util.NoSuchElementException
	at java.util.Vector.firstElement(Unknown Source)
	at com.hsbc.objectpool.general.ObjectPool.borrowObject(ObjectPool.java:57)
	at com.hsbc.objectpool.general.TestGeneralObjectPool.run(TestGeneralObjectPool.java:44)
	at java.lang.Thread.run(Unknown Source)
Exception in thread "Thread-2" java.util.NoSuchElementException
	at java.util.Vector.firstElement(Unknown Source)
	at com.hsbc.objectpool.general.ObjectPool.borrowObject(ObjectPool.java:57)
	at com.hsbc.objectpool.general.TestGeneralObjectPool.run(TestGeneralObjectPool.java:44)
	at java.lang.Thread.run(Unknown Source)
Thread-0尝试借出对象
pool中有可用的对象1个
Thread-0, 2
Thread-0尝试借出对象
pool中有可用的对象1个
Thread-0, 3
Thread-0尝试借出对象
pool中有可用的对象1个
Thread-0, 4
Thread-0尝试借出对象
pool中有可用的对象1个
Thread-0, 5
Thread-0尝试借出对象
pool中有可用的对象1个
Thread-0, 6
Thread-0尝试借出对象
pool中有可用的对象1个
Thread-0, 7
Thread-0尝试借出对象
pool中有可用的对象1个
Thread-0, 8
Thread-0尝试借出对象
pool中有可用的对象1个
Thread-0, 9
Thread-0 线程运行结束!



加载中
0
Andre.Z
Andre.Z

notifyAll()唤醒所有等待的线程,然后,混乱了,换成notify(),随机唤醒一个线程。
btw:你输出的时候带时间和线程名称,好分辨

黑菜妞妞
黑菜妞妞
@Andre.Z : 我再仔细的看看吧。O(∩_∩)O谢谢
Andre.Z
Andre.Z
@黑菜妞妞 : 注意锁的用法,以及没用到锁会产生什么后果。你取出的时候,那个锁有问题吧
Andre.Z
Andre.Z
@黑菜妞妞 : getObject????
Andre.Z
Andre.Z
@黑菜妞妞 : 我只是随便看了下,发现那个问题而已。。。
黑菜妞妞
黑菜妞妞
我改成notify()之后,还是有异常。表示很不理解
下一页
0
huzorro
huzorro
borrowObject 方法和 returnObject方法 这两个方法都应该是synchronized的
0
huzorro
huzorro
如果synchronized效率低的话, 可以试试JUC的lock
0
huzorro
huzorro

引用来自“Andre.Z”的答案

notifyAll()唤醒所有等待的线程,然后,混乱了,换成notify(),随机唤醒一个线程。
btw:你输出的时候带时间和线程名称,好分辨

必须使用 notifyAll() 不能使用 notify()
0
芙蓉镇
芙蓉镇

ObjectPool的public Object borrowObject()的pool.size()>0的分支有问题,即使有pool.size()>0条件那么在取Object时候仍然要判断是否取成功,因为会有并发问题:别的线程取走最后一个Object以后,另一个线程再取就该出错了。建议增加一个fetchLock,在borrowObject中用fetchLock作同步:

        synchronized (fetchLock) {
            while (pool is empty) {
                fetchLock.wait();
            }
            在这里从pool中获取Object
        }

0
huzorro
huzorro
把borrowObject 方法和 returnObject方法里的对象锁 改为方法锁, 是最快的处理方式
0
Andre.Z
Andre.Z

引用来自“huzorro”的答案

引用来自“Andre.Z”的答案

notifyAll()唤醒所有等待的线程,然后,混乱了,换成notify(),随机唤醒一个线程。
btw:你输出的时候带时间和线程名称,好分辨

必须使用 notifyAll() 不能使用 notify()

notifyAll把所有等待的线程都唤醒了,又引发一轮争抢。
如果wait之后有锁机制,只有一个线程能获取到资源,其它的又继续wait,浪费资源。
如果wait之后没有锁机制的话,会出现什么情况?

0
黑菜妞妞
黑菜妞妞
谢谢大家给的答案,我会再试试的,谢谢喽~~有不懂的地方还是会继续问的O(∩_∩)O哈!
0
JavaGG
JavaGG
看容器是用 Vector 的性能一定有问题
0
JavaGG
JavaGG
import java.util.concurrent.ConcurrentLinkedQueue;
import java.util.concurrent.locks.ReentrantLock;

/**
 * 对象池工厂
 * 
 * @author javagg
 * 
 */
public class ObjectPoolFactroy {

	private static ConcurrentHashMap<Class, PoolObj> pools = new ConcurrentHashMap<Class, PoolObj>(false);
	private static ReentrantLock lock = new ReentrantLock();

	/**
	 * 从池中取出一个对象
	 * 
	 * @param obj
	 * @return
	 *@date 2009-12-3
	 *@author eric.chan
	 */
	public static Object poll(Class obj) {
		PoolObj pool = pools.get(obj);
		if (pool == null) {
			lock.lock();
			try {
				if (pools.get(obj) == null) {
					pool = new PoolObj();
					pools.put(obj, pool);
				}
			} finally {
				lock.unlock();
			}
		}
		return pool.poll(obj);
	}

	/**
	 * 把对象归还到池中
	 * 
	 * @param obj
	 *@date 2009-12-3
	 *@author eric.chan
	 */
	public static void offer(Object obj) {
		PoolObj pool = pools.get(obj.getClass());
		if (pool == null)
			throw new RuntimeException(obj.getClass() + " is not poll form pools ");
		pool.offer(obj);
	}

	public static void printPool() {
		StringBuilder sb = new StringBuilder();
		for (Class c : pools.keySet()) {
			sb.append(c.getName()).append("  ").append(pools.get(c).size()).append("\n");
		}
		System.out.println(sb.toString());
	}
}

class PoolObj {
	ConcurrentLinkedQueue<Object> queue = new ConcurrentLinkedQueue<Object>();
//	ArrayList<Object> list = new SyncArrayList<Object>(16);
	volatile int count=0;
	public Object poll(Class cla) {
		Object obj = queue.poll();
		if (obj == null) {
			try {
				obj = cla.newInstance();
			} catch (Exception e) {
				e.printStackTrace();
			}
			count++;
//			list.add(obj);
		}
		return obj;
	}

	public void offer(Object obj) {
		queue.offer(obj);
	}

	public int size() {
		return count;
	}
}
这个是我以前写的,不过未测试过性能
JavaGG
JavaGG
@黑菜妞妞 : 不好意思,你改成ConcurrentHashMap吧,一样的
黑菜妞妞
黑菜妞妞
GConcurrentHashMap这个类是神马呢?也给贴出来吧~~(*^__^*) 嘻嘻……
黑菜妞妞
黑菜妞妞
O(∩_∩)O哈哈~O(∩_∩)O谢谢啦~~我去试试~~
返回顶部
顶部