物件池、資料庫連線池原理
阿新 • • 發佈:2018-12-04
一、一點說明:
(本文的知識點來自C#執行緒參考手冊)
物件池在企業軟體中非常常見,為了提供應用的效能,必須控制物件例項的建立。比如建立資料庫連線物件,每一次建立的代價非常高昂,每一次使用資料庫都需要連線資料庫,代價非常高昂,因此有了資料庫連線池,每一次一個連線被建立之後不是就馬上釋放,下一次使用的時候重新建立,而是在使用完畢之後重新放回資料庫連線池,當需要再次使用資料庫的時候,從資料庫連線池拿取空閒的資料庫連線。
需要資料庫連線池的原因:
1、建立一個物件的代價高昂:
- 建立的時候佔用較多的記憶體,記憶體的分配會降低應用程式的效能
- 需要使用較長的時間
2、建立的物件具備可複用性
二、實現物件池:
一個物件池的建立:
- 兩個存放物件的集合:一個存放正在使用的物件集合,一個存放空閒的物件集合;
- 兩個變數:一個變數值指定為空閒物件集合進行回收釋放記憶體和資源的時間間隔,一個變數為最後一次對空間物件進行回收的時間;
- 一個建立物件的方法
- 一個檢查物件是否空閒的方法啊
- 一個對需要回收釋放資源的物件進行失效的方法;
- 一個從物件池取物件的方法;
- 一個把物件放回物件池的方法;
- 一個定期回收空閒物件集合中需要失效的物件。
下面看基類:
public abstract class ObjectPool {private long _lastCheckOutTime; private static Dictionary<object, long> lockObject; private static Dictionary<object, long> freeObject; internal static long GARBAGE_INTERVAL = 2 * 60 * 1000; // 靜態建構函式,先於其他建構函式被呼叫 static ObjectPool() { lockObject= new Dictionary<object, long>(); freeObject = new Dictionary<object, long>(); } internal ObjectPool() { _lastCheckOutTime = DateTime.Now.Ticks; Timer timer = new Timer(new TimerCallback(CollecttGarbage),null,0,GARBAGE_INTERVAL); } protected abstract object Create(); protected abstract bool Validate(object o); protected abstract void Expire(object o); internal object GetObjectFromPool() { long now = DateTime.Now.Ticks; _lastCheckOutTime = now; object o = null; lock (this) { try { foreach (var item in freeObject) { o = item.Key; if (Validate(o)) { freeObject.Remove(item); lockObject.Add(o, now); return item; } else { freeObject.Remove(o); Expire(o); o = null; } } }catch(Exception ex) { o = Create(); lockObject.Add(o, now); } } return o; } internal void ReturnObjectToPool(object o) { if (o != null) { lock (this) { lockObject.Remove(o); freeObject.Add(o, DateTime.Now.Ticks); } } } protected virtual void CollecttGarbage(object state) { lock (this) { object o; long now = DateTime.Now.Ticks; try { foreach (var item in freeObject) { o = item.Key; if ((now - item.Value) > GARBAGE_INTERVAL) { freeObject.Remove(item); Expire(o); o = null; } } }catch(Exception ex) { } } } }
從程式碼可以看出:
1、我們在基類實現的三個方法:CollecttGarbage ReturnObjectToPool GetObjectFromPool都是加了鎖的,原因是在執行這三個方法的時候,操作的物件集合可能同時被操縱(減少、增加、或者移除),而在這三個方法中我們是不希望出現競爭條件的。
2、Create Expire Validate 三個方法都是虛方法,在基類裡面沒有進行實現,因為這三個方法是需要根據不同的業務場景根據不同型別的物件池編寫的。另外,這三個方法的邏輯控制使用了模板操作方法設計模式。
下面看資料庫連線池的簡單實現:
public sealed class DBConnectionSingleton:ObjectPool { // 私有化的建構函式 private DBConnectionSingleton() { } // 使用單例模式,建立唯一物件。 public static readonly DBConnectionSingleton instance = new DBConnectionSingleton(); private static string ConnectionString { get; } protected override bool Validate(object o) { try { SqlConnection temp = new SqlConnection(ConnectionString); return !(temp.State.Equals(System.Data.ConnectionState.Closed)); }catch(SqlException ex) { return false; } } protected override void Expire(object o) { try { ((SqlConnection)o).Close(); }catch(Exception ex) { } } protected override object Create() { SqlConnection conn = new SqlConnection(ConnectionString); conn.Open(); return (conn); } }
end===