用C#建立通用对象池[1]
在系统设计中,经常会使用“池”的概念。比如数据库连接池,socket连接池,线程池,组件队列。“池”可以节省对象重复创建和初始化所耗费的时间,可以简化对象获取和使用的过程。对于那些被系统频繁请求和使用的对象,如果使用这种机制,可以使系统性能得到很大提高。特别象数据库连接这种对象,客户端与数据库服务器端建立连接时,是比较慢的,如果每次进行数据库操作,都要先进行数据库连接,系统效率将非常低下。
“池”的概念就是将被使用的对象事先创建好,保存在列表中,供客户端取用。当客户端取得一个对象时,这个对象就已经是按照特定上下文环境初始化好,马上即可使用的了。当客户端使用完毕,需要将对象归还给“池”,最后,在系统生命期结束时,由“池”统一释放这些对象。从另一个概念上来说,这也是一种“以空间换时间”的做法,我们在内存中保存一系列整装待命的对象,供人随时差遣。与系统效率相比,这些对象所占用的内存空间太微不足道了。
“池”的结构是通用的,就是不管他里面保存的是哪一种对象,他的工作方法都基本不变。无非是初始化一系列对象,然后提供一个获取可用对象,一个归还对象的接口。
基于这种考虑,我们可以建立一个通用的对象池,只要某些对象符合“一些基本要求”(这个基本要求,可以使用Interface模式来限定),就可以使用通用对象池来存取和管理。
用C#建立通用对象池[2]创建一个接口,用于限定对象池中所保存的对象的基本行为:
|
public interface IDynamicObject { void Create(Object param); Object GetInnerObject(); bool IsValidate(); void Release(); }
|
我们在对象池中存放的对象,必须继承上面的接口,并实现接口定义的每一个方法。
Create方法中,用户可以用来创建实际的对象,如建立数据库连接,并打开这个连接;GetInnerObject方法,使用户可以返回这个实际的对象,如一个SqlConnection对象;IsValidate方法是用来判断用户自定义对象的有效性的,是对象池决定是否重新创建对象的标志;Release方法中,用户可以进行资源释放工作。
有了上面的接口定义,为我们可以在列表中保存用户自定义对象打下了基础。下面就是要实现这个ObjectPool了。
用户自定义对象在我们的ObjectPool中,可以用列表存储,如ArrayList或者Hashtable,为了表示每个用户对象的状态,我们还需要将用户自定义对象包装一下,然后在放到列表中保存。下面定义了一个ObjectPool类的子类,用于包装用户自定义对象:
|
private class PoolItem { private IDynamicObject _object; private bool _bUsing; private Type _type; private Object _CreateParam;
public PoolItem(Type type,Object param) { _type = type; _CreateParam = param; Create(); }
private void Create() { _bUsing = false;
_object = (IDynamicObject)System.Activator.CreateInstance(_type); _object.Create(_CreateParam);
} public void Recreate() { _object.Release(); Create(); } public void Release() { _object.Release(); } public Object InnerObject { get{return _object.GetInnerObject();} } public int InnerObjectHashcode { get{return InnerObject.GetHashCode();} } public bool IsValidate { get{return _object.IsValidate();} } public bool Using { get{return _bUsing;} set { _bUsing = value; } } }// class PoolItem
|
这个类,一个关键的属性是Using,该属性表示对象是否正在被被用户使用。注意,PoolItem创建时,接受一个Object类型的Param参数,这个参数最后被传递给用户自定义对象的Create方法。用户可以利用这一点,在创建ObjectPool时指定一些参数,供其自定义对象在创建时使用。比如创建SocketPool时,将服务器IP,端口通过Param传递给自定义对象的Create方法,用户就可以在Create方法中连接指定的服务器了。
以下是ObjectPool的具体实现代码:
|
public sealed class ObjectPool { private Int32 _nCapacity; private Int32 _nCurrentSize; private Hashtable _listObjects; private ArrayList _listFreeIndex; private ArrayList _:listUsingIndex; private Type _typeObject; private Object _objCreateParam;
public ObjectPool(Type type, Object create_param, Int32 init_size, Int32 capacity) { if(init_size < 0 || capacity < 1 || init_size>capacity) { throw(new Exception("Invalid parameter!")); }
_nCapacity = capacity; _listObjects = new Hashtable(capacity); _listFreeIndex = new ArrayList(capacity); _listUsingIndex = new ArrayList(capacity); _typeObject = type; _objCreateParam = create_param;
for(int i=0;i<init_size;i++) { PoolItem pitem = new PoolItem(type,create_param); _listObjects.Add(pitem.InnerObjectHashcode,pitem); _listFreeIndex.Add(pitem.InnerObjectHashcode); }
_nCurrentSize = _listObjects.Count; }
public void Release() { lock(this) { foreach(DictionaryEntry de in _listObjects) { ( (PoolItem)de.Value ).Release(); } _listObjects.Clear(); _listFreeIndex.Clear(); _listUsingIndex.Clear(); } }
public Int32 CurrentSize { get{return _nCurrentSize;} }
public Int32 ActiveCount { get{return _listUsingIndex.Count;} }
public Object GetOne() { lock(this) { if(_listFreeIndex.Count == 0) { if(_nCurrentSize == _nCapacity) { return null; }
PoolItem pnewitem = new PoolItem(_typeObject,_objCreateParam); _listObjects.Add(pnewitem.InnerObjectHashcode,pnewitem); _listFreeIndex.Add(pnewitem.InnerObjectHashcode); _nCurrentSize++; }
Int32 nFreeIndex = (Int32)_listFreeIndex[0]; PoolItem pitem = (PoolItem)_listObjects[nFreeIndex]; _listFreeIndex.RemoveAt(0); _listUsingIndex.Add(nFreeIndex);
if(!pitem.IsValidate) { pitem.Recreate(); } pitem.Using = true;
return pitem.InnerObject; } }
public void FreeObject(Object obj) { lock(this) { int key = obj.GetHashCode(); if(_listObjects.ContainsKey(key)) { PoolItem item = (PoolItem)_listObjects[key]; item.Using = false; _listUsingIndex.Remove(key); _listFreeIndex.Add(key); } } }
public Int32 DecreaseSize(Int32 size) { Int32 nDecrease = size; lock(this) { if(nDecrease <= 0) { return 0; } if(nDecrease > _listFreeIndex.Count) { nDecrease = _listFreeIndex.Count; } for(int i=0;i<nDecrease;i++) { _listObjects.Remove(_listFreeIndex[i]); }
_listFreeIndex.Clear(); _listUsingIndex.Clear();
foreach(DictionaryEntry de in _listObjects) { PoolItem pitem = (PoolItem)de.Value; if(pitem.Using) { _listUsingIndex.Add(pitem.InnerObjectHashcode); } else { _listFreeIndex.Add(pitem.InnerObjectHashcode); } }
} _nCurrentSize -= nDecrease; return nDecrease; } } |

浙公网安备 33010602011771号