在Web中Session的功能很好用,因而想Winform中實現該功能,典型應用場景則是登錄成功後,當一段時間不操做,則該會話過時,提示從新登錄。緩存
測試代碼多線程
示例說明:登錄進去10s不操做或者訪問Cache後10秒不操做,則會提示登錄超時測試
1. 設計CacheContainer類,使用Dictionary存放變量,並添加互斥鎖SyncRoot,避免多線程操做帶來異常。this
2. CacheContainer內部的變量,若是持續10秒(測試使用的默認值)沒有訪問或操做,則自動移除該變量,並觸發回調。spa
3. 當程序訪問CacheContainer內部的變量,過時時間從當前時間開始計時。線程
4. 變量第一次計時在加入CacheContainer時。設計
具體代碼以下:code
using System; using System.Collections.Generic; using System.Text; using System.Threading; namespace WindowsFormsApplication1 { public sealed class CacheContainer { //互斥鎖 private object SyncRoot = new object(); //對象字典 private Dictionary<string, CacheObj> dic = new Dictionary<string, CacheObj>(); internal class CacheObj : IDisposable { //公有變量 public object Value { get; set; } public int Expired { get; set; } public WaitCallback callback { get; set; } public AutoResetEvent ar = new AutoResetEvent(false); public TimeSpan Timeout { get { return TimeSpan.FromSeconds(Expired); } } public CacheObj(object value, int expired = 10) { Value = value; Expired = expired; callback = new WaitCallback((obj) => { Console.WriteLine("{0}:已過時,過時時間:{1}", obj, DateTime.Now); }); } public void Dispose() { GC.SuppressFinalize(this); } ~CacheObj() { Dispose(); } } private static CacheContainer container = new CacheContainer(); private CacheContainer() { } public static CacheContainer GetInstance() { return container; } public object this[string key] { get { //訪問變量成功,則時間從新計時 CacheObj cache; lock (SyncRoot) { if (dic.TryGetValue(key, out cache)) { cache.ar.Set(); return cache.Value; } } return null; } set { //經過屬性添加參數,有則覆蓋,無則添加,操做完畢從新計時 CacheObj cache; lock (SyncRoot) { if (dic.TryGetValue(key, out cache)) { cache.Value = value; cache.ar.Set(); } else Add(key, value); } } } public void Add(string key, object value) { lock (SyncRoot) dic.Add(key, new CacheObj(value)); AutoCheck(key); } public void Add(string key, object value, int expired) { lock (SyncRoot) dic.Add(key, new CacheObj(value, expired)); AutoCheck(key); } public void Add(string key, object value, int expired, WaitCallback callback) { lock (SyncRoot) dic.Add(key, new CacheObj(value, expired) { callback = callback }); AutoCheck(key); } private void AutoCheck(string key) { //開啓一個子線程去控制變量的過時 ThreadPool.QueueUserWorkItem(new WaitCallback((obj) => { CacheObj tmpCache; while (true) { //從字典中取出對象 lock (SyncRoot) tmpCache = dic[key]; //打印變量過時時間 Console.WriteLine("{0} 等待銷燬變量 時間爲:{1}秒", DateTime.Now, tmpCache.Expired); //記錄開始時間 var timeStart = DateTime.Now; //中斷,超時時間一到,自動向下執行 tmpCache.ar.WaitOne(TimeSpan.FromSeconds(tmpCache.Expired)); //檢查時間是否已經達到超時時間,超時則移除該信息,並觸發回調 if ((DateTime.Now - timeStart) >= tmpCache.Timeout) { lock (SyncRoot) dic.Remove(key); if (tmpCache.callback != null) tmpCache.callback(tmpCache.Value); break; } } })); } public void Remove(string key) { lock (SyncRoot) { CacheObj cache; if (dic.TryGetValue(key, out cache)) { cache.Expired = 0; cache.ar.Set(); } } } } }
CacheContainer中的變量,均是在線程池裏有個線程去檢測它,也就是說有10個變量,線程池裏就會多10個子線程,這樣會不會不太好。orm
該方法僅是拋磚引玉,不知道在Winform中實現緩存變量xx分鐘這樣的功能有沒有更好的方法,歡迎賜教,謝謝!對象