上一篇文章我們講訴了自定義線程執行器和任務處理器
我們繼續來講解自定義線程的定時執行器,我們在很多場景下需要做到某些狀態或者數據進行更新,如果事情很多很雜,很時候時候會創建很多不同的定時器那么勢必會照成系統的消耗和性能低下的問題!今天我們來解決這一問題。
首先我們創建定時任務執行器基類
1 /// <summary> 2 /// 3 /// </summary> 4 public abstract class TimerTaskBase : BaseTask 5 { 6 7 8 /// <summary> 9 /// 開始執行的時間 10 /// </summary> 11 public long StartTime { get; set; } 12 13 /// <summary> 14 /// 是否一開始執行一次 15 /// </summary> 16 public bool IsStartAction { get; set; } 17 18 /// <summary> 19 /// 結束時間 20 /// </summary> 21 public long EndTime { get; set; } 22 23 /// <summary> 24 /// 執行次數 25 /// </summary> 26 public int ActionCount { get; set; } 27 28 /// <summary> 29 /// 已經執行的次數 30 /// </summary> 31 public int AActionCount { get; set; } 32 33 /// <summary> 34 /// 間隔執行時間 35 /// </summary> 36 public int IntervalTime { get; set; } 37 38 /// <summary> 39 /// 制定執行次數的定時任務 40 /// </summary> 41 /// <param name="startTime">0表示立即執行,否則延遲執行,填寫開始時間</param> 42 /// <param name="intervalTime">執行間隔時間,小於10毫秒,當10毫秒處理</param> 43 /// <param name="isStartAction">是否一開始執行一次</param> 44 /// <param name="actionCount">需要執行的次數</param> 45 public TimerTaskBase(long startTime, int intervalTime, bool isStartAction, int actionCount) 46 { 47 this.StartTime = startTime; 48 this.IntervalTime = intervalTime; 49 this.IsStartAction = isStartAction; 50 this.ActionCount = actionCount; 51 this.EndTime = 0; 52 } 53 54 /// <summary> 55 /// 制定結束時間的定時任務 56 /// </summary> 57 /// <param name="startTime">0表示立即執行,否則延遲執行,填寫開始時間</param> 58 /// <param name="intervalTime">執行間隔時間,小於10毫秒,當10毫秒處理</param> 59 /// <param name="endTime">執行結束時間</param> 60 /// <param name="isStartAction">是否一開始執行一次</param> 61 public TimerTaskBase(long startTime, int intervalTime, long endTime, bool isStartAction) 62 { 63 this.StartTime = startTime; 64 this.IntervalTime = intervalTime; 65 this.IsStartAction = isStartAction; 66 this.ActionCount = 0; 67 this.EndTime = endTime; 68 } 69 70 /// <summary> 71 /// 制定開始時間,無限執行任務 72 /// </summary> 73 /// <param name="startTime">0表示立即執行,否則延遲執行,填寫開始時間</param> 74 /// <param name="intervalTime">執行間隔時間,小於10毫秒,當 10 毫秒處理 建議 10 毫秒的倍數</param> 75 /// <param name="isStartAction">是否一開始執行一次</param> 76 public TimerTaskBase(long startTime, int intervalTime, bool isStartAction) 77 { 78 this.StartTime = startTime; 79 this.IntervalTime = intervalTime; 80 this.IsStartAction = isStartAction; 81 this.ActionCount = 0; 82 this.EndTime = 0; 83 } 84 85 public TimerTaskBase() 86 { 87 // TODO: Complete member initialization 88 } 89 }
上面的代碼實現了,開始時間,間隔時間,結束時間和執行次數 的控制
那么我們來看看定時器線程的設計
1 public class TimerThread 2 { 3 public TimerThread() 4 { 5 System.Threading.Thread thread = new System.Threading.Thread(new System.Threading.ThreadStart(Run)); 6 thread.IsBackground = true; 7 thread.Start(); 8 } 9 10 /// <summary> 11 /// 任務隊列 12 /// </summary> 13 private List<TimerTaskBase> taskQueue = new List<TimerTaskBase>(); 14 15 /// <summary> 16 /// 加入任務 17 /// </summary> 18 /// <param name="t"></param> 19 public void AddTask(TimerTaskBase t) 20 { 21 if (t.IsStartAction) 22 { 23 //滿足添加隊列前先執行一次 24 t.Run(); 25 } 26 lock (taskQueue) 27 { 28 taskQueue.Add(t); 29 } 30 } 31 32 public long GetDate() 33 { 34 return Convert.ToInt64(System.DateTime.Now.ToString("yyyyMMddHHmmssfff")); 35 } 36 37 //這里的線程同步器,不是用來通知的, 38 //只是用來暫停的,因為Thread.Sleep() 消耗開銷比較大 39 ManualResetEvent mre = new ManualResetEvent(false); 40 41 /// <summary> 42 /// 重構函數執行器 43 /// </summary> 44 private void Run() 45 { 46 ///無限循環執行函數器 47 while (true) 48 { 49 if (taskQueue.Count > 0) 50 { 51 IEnumerable<TimerTaskBase> collections = null; 52 lock (taskQueue) 53 { 54 //拷貝一次隊列 預防本次輪訓檢查的時候有新的任務添加 55 //否則循環會出錯 集合被修改無法迭代 56 collections = new List<TimerTaskBase>(taskQueue); 57 } 58 //開始迭代 59 foreach (TimerTaskBase tet in collections) 60 { 61 int actionCount = tet.AActionCount; 62 long timers = GetDate(); 63 if ((tet.EndTime > 0 && timers > tet.EndTime) || (tet.ActionCount > 0 && actionCount >= tet.ActionCount)) 64 { 65 //任務過期 66 lock (taskQueue) 67 { 68 taskQueue.Remove(tet); 69 } 70 continue; 71 } 72 //獲取最后一次的執行時間 73 long lastactiontime = tet.TempAttribute.getlongValue("lastactiontime"); 74 if (lastactiontime != 0 && Math.Abs(timers - lastactiontime) < tet.IntervalTime) 75 { 76 continue; 77 } 78 //記錄出來次數 79 tet.AActionCount++; 80 //記錄最后執行的時間 81 tet.TempAttribute.setValue("lastactiontime", timers); 82 83 //上面的代碼執行情況是非常幾乎不用考慮消耗問題 84 85 //下面是任務的執行需要考慮消耗, 86 87 //這里我們不考慮執行耗時問題, 88 //我們我這里沒有涉及到后台線程池 89 //也沒有具體的業務邏輯,所以都放到這里統一執行 90 tet.Run(); 91 } 92 } 93 //暫停10毫秒后再次檢查 94 mre.WaitOne(10); 95 } 96 } 97 }
定時器為什么沒有使用上一篇文章講訴的自定義線程呢,是因為,上一篇文章的自定義線程是基於隊列處理的,先進先出執行,而我們的定時器任務並非是基於隊列的。所以需要單獨定義。
那么我們先來實現一個每一秒執行的任務,
1 /// <summary> 2 /// 每秒執行的任務 3 /// </summary> 4 public class SecondsTimerTask : TimerTaskBase 5 { 6 /// <summary> 7 /// 定義一秒執行一次的 8 /// </summary> 9 public SecondsTimerTask() 10 : base(0, 1000, false) 11 { 12 13 } 14 15 public override void Run() 16 { 17 Console.WriteLine(DateTime.Now.ToString("HH:mm:ss:ffff: ") + "我是 每秒 執行的任務"); 18 } 19 }
我們來測試一下看看效果
1 class Program 2 { 3 static void Main(string[] args) 4 { 5 TimerThread timerThread = new TimerThread(); 6 timerThread.AddTask(new SecondsTimerTask()); 7 Console.ReadLine(); 8 } 9 }

還算是我們的預想的效果吧,每秒執行一次
接下來我們創建每分鍾執行一次
1 public class MinuteTimerTask : TimerTaskBase 2 { 3 /// <summary> 4 /// 定義一分鍾執行一次的 5 /// </summary> 6 public MinuteTimerTask() 7 : base(0, 1000 * 60, false) 8 { 9 10 } 11 12 public override void Run() 13 { 14 Console.WriteLine(DateTime.Now.ToString("HH:mm:ss:ffff: ") + "我是 每分鍾 執行的任務"); 15 } 16 }
按照執行次數的定時器
1 /// <summary> 2 /// 我是按照執行次數結束的 3 /// </summary> 4 public class CountTimerTask : TimerTaskBase 5 { 6 /// <summary> 7 /// 定義一秒執行一次的 8 /// </summary> 9 public CountTimerTask() 10 : base(0, 1000, false, 10) 11 { 12 13 } 14 15 16 public override void Run() 17 { 18 Console.WriteLine(DateTime.Now.ToString("HH:mm:ss:ffff: ") + "我是 次數 執行的任務 我要執行:" + this.ActionCount + " 次 執行了: " + this.AActionCount + " 次"); 19 } 20 }
測試一下
1 class Program 2 { 3 static void Main(string[] args) 4 { 5 TimerThread timerThread = new TimerThread(); 6 timerThread.AddTask(new SecondsTimerTask()); 7 8 timerThread.AddTask(new MinuteTimerTask()); 9 timerThread.AddTask(new CountTimerTask()); 10 11 Console.ReadLine(); 12 } 13 }
運行結果:

到此我們的定時器線程執行器已經完成,滿足我們需要做到定時更新狀態,合作檢查數據等應用場景!
不知道對你有沒有幫助呢?
請不了吝嗇你的小手,給予一個評論吧,幫助到你了請給與鼓勵,如果有不足之處還請多多指教!
