上一篇文章我們講訴了自定義線程執行器和任務處理器
我們繼續來講解自定義線程的定時執行器,我們在很多場景下需要做到某些狀態或者數據進行更新,如果事情很多很雜,很時候時候會創建很多不同的定時器那么勢必會照成系統的消耗和性能低下的問題!今天我們來解決這一問題。
首先我們創建定時任務執行器基類
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 initialization88 }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 Program2 {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 o
新聞熱點
疑難解答