C# 线程系列三 定时器线程
上一篇文章我们讲诉了自定义线程执行器和任务处理器
我们继续来讲解自定义线程的定时执行器,我们在很多场景下需要做到某些状态或者数据进行更新,如果事情很多很杂,很时候时候会创建很多不同的定时器那么势必会照成系统的消耗和性能低下的问题!今天我们来解决这一问题。
首先我们创建定时任务执行器基类
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 }
运行结果:
到此我们的定时器线程执行器已经完成,满足我们需要做到定时更新状态,合作检查数据等应用场景!
不知道对你有没有帮助呢?
请不了吝啬你的小手,给予一个评论吧,帮助到你了请给与鼓励,如果有不足之处还请多多指教!
跪求保留标示符 /** * @author: Troy.Chen(失足程序员, 15388152619) * @version: 2021-07-20 10:55 **/ C#版本代码 vs2010及以上工具可以 java 开发工具是netbeans 和 idea 版本,只有项目导入如果出现异常,请根据自己的工具调整 提供免费仓储。 最新的代码地址:↓↓↓ https://gitee.com/wuxindao 觉得我还可以,打赏一下吧,你的肯定是我努力的最大动力