C# 线程系列三 定时器线程
上一篇文章我们讲诉了自定义线程执行器和任务处理器
我们继续来讲解自定义线程的定时执行器,我们在很多场景下需要做到某些状态或者数据进行更新,如果事情很多很杂,很时候时候会创建很多不同的定时器那么势必会照成系统的消耗和性能低下的问题!今天我们来解决这一问题。
首先我们创建定时任务执行器基类
/// <summary> /// /// </summary> public abstract class TimerTaskBase : BaseTask { /// <summary> /// 开始执行的时间 /// </summary> public long StartTime { get; set; } /// <summary> /// 是否一开始执行一次 /// </summary> public bool IsStartAction { get; set; } /// <summary> /// 结束时间 /// </summary> public long EndTime { get; set; } /// <summary> /// 执行次数 /// </summary> public int ActionCount { get; set; } /// <summary> /// 已经执行的次数 /// </summary> public int AActionCount { get; set; } /// <summary> /// 间隔执行时间 /// </summary> public int IntervalTime { get; set; } /// <summary> /// 制定执行次数的定时任务 /// </summary> /// <param name="startTime">0表示立即执行,否则延迟执行,填写开始时间</param> /// <param name="intervalTime">执行间隔时间,小于10毫秒,当10毫秒处理</param> /// <param name="isStartAction">是否一开始执行一次</param> /// <param name="actionCount">需要执行的次数</param> public TimerTaskBase(long startTime, int intervalTime, bool isStartAction, int actionCount) { this.StartTime = startTime; this.IntervalTime = intervalTime; this.IsStartAction = isStartAction; this.ActionCount = actionCount; ; } /// <summary> /// 制定结束时间的定时任务 /// </summary> /// <param name="startTime">0表示立即执行,否则延迟执行,填写开始时间</param> /// <param name="intervalTime">执行间隔时间,小于10毫秒,当10毫秒处理</param> /// <param name="endTime">执行结束时间</param> /// <param name="isStartAction">是否一开始执行一次</param> public TimerTaskBase(long startTime, int intervalTime, long endTime, bool isStartAction) { this.StartTime = startTime; this.IntervalTime = intervalTime; this.IsStartAction = isStartAction; ; this.EndTime = endTime; } /// <summary> /// 制定开始时间,无限执行任务 /// </summary> /// <param name="startTime">0表示立即执行,否则延迟执行,填写开始时间</param> /// <param name="intervalTime">执行间隔时间,小于10毫秒,当 10 毫秒处理 建议 10 毫秒的倍数</param> /// <param name="isStartAction">是否一开始执行一次</param> public TimerTaskBase(long startTime, int intervalTime, bool isStartAction) { this.StartTime = startTime; this.IntervalTime = intervalTime; this.IsStartAction = isStartAction; ; ; } public TimerTaskBase() { // TODO: Complete member initialization } }
上面的代码实现了,开始时间,间隔时间,结束时间和执行次数 的控制
那么我们来看看定时器线程的设计
public class TimerThread { public TimerThread() { System.Threading.Thread thread = new System.Threading.Thread(new System.Threading.ThreadStart(Run)); thread.IsBackground = true; thread.Start(); } /// <summary> /// 任务队列 /// </summary> private List<TimerTaskBase> taskQueue = new List<TimerTaskBase>(); /// <summary> /// 加入任务 /// </summary> /// <param name="t"></param> public void AddTask(TimerTaskBase t) { if (t.IsStartAction) { //满足添加队列前先执行一次 t.Run(); } lock (taskQueue) { taskQueue.Add(t); } } public long GetDate() { return Convert.ToInt64(System.DateTime.Now.ToString("yyyyMMddHHmmssfff")); } //这里的线程同步器,不是用来通知的, //只是用来暂停的,因为Thread.Sleep() 消耗开销比较大 ManualResetEvent mre = new ManualResetEvent(false); /// <summary> /// 重构函数执行器 /// </summary> private void Run() { ///无限循环执行函数器 while (true) { ) { IEnumerable<TimerTaskBase> collections = null; lock (taskQueue) { //拷贝一次队列 预防本次轮训检查的时候有新的任务添加 //否则循环会出错 集合被修改无法迭代 collections = new List<TimerTaskBase>(taskQueue); } //开始迭代 foreach (TimerTaskBase tet in collections) { int actionCount = tet.AActionCount; long timers = GetDate(); && timers > tet.EndTime) || (tet.ActionCount > && actionCount >= tet.ActionCount)) { //任务过期 lock (taskQueue) { taskQueue.Remove(tet); } continue; } //获取最后一次的执行时间 long lastactiontime = tet.TempAttribute.getlongValue("lastactiontime"); && Math.Abs(timers - lastactiontime) < tet.IntervalTime) { continue; } //记录出来次数 tet.AActionCount++; //记录最后执行的时间 tet.TempAttribute.setValue("lastactiontime", timers); //上面的代码执行情况是非常几乎不用考虑消耗问题 //下面是任务的执行需要考虑消耗, //这里我们不考虑执行耗时问题, //我们我这里没有涉及到后台线程池 //也没有具体的业务逻辑,所以都放到这里统一执行 tet.Run(); } } //暂停10毫秒后再次检查 mre.WaitOne(); } } }
定时器为什么没有使用上一篇文章讲诉的自定义线程呢,是因为,上一篇文章的自定义线程是基于队列处理的,先进先出执行,而我们的定时器任务并非是基于队列的。所以需要单独定义。
那么我们先来实现一个每一秒执行的任务,
/// <summary> /// 每秒执行的任务 /// </summary> public class SecondsTimerTask : TimerTaskBase { /// <summary> /// 定义一秒执行一次的 /// </summary> public SecondsTimerTask() : , , false) { } public override void Run() { Console.WriteLine(DateTime.Now.ToString("HH:mm:ss:ffff: ") + "我是 每秒 执行的任务"); } }
我们来测试一下看看效果
class Program { static void Main(string[] args) { TimerThread timerThread = new TimerThread(); timerThread.AddTask(new SecondsTimerTask()); Console.ReadLine(); } }
还算是我们的预想的效果吧,每秒执行一次
接下来我们创建每分钟执行一次
public class MinuteTimerTask : TimerTaskBase { /// <summary> /// 定义一分钟执行一次的 /// </summary> public MinuteTimerTask() : , * , false) { } public override void Run() { Console.WriteLine(DateTime.Now.ToString("HH:mm:ss:ffff: ") + "我是 每分钟 执行的任务"); } }
按照执行次数的定时器
/// <summary> /// 我是按照执行次数结束的 /// </summary> public class CountTimerTask : TimerTaskBase { /// <summary> /// 定义一秒执行一次的 /// </summary> public CountTimerTask() : , , ) { } public override void Run() { Console.WriteLine(DateTime.Now.ToString("HH:mm:ss:ffff: ") + "我是 次数 执行的任务 我要执行:" + this.ActionCount + " 次 执行了: " + this.AActionCount + " 次"); } }
测试一下
class Program { static void Main(string[] args) { TimerThread timerThread = new TimerThread(); timerThread.AddTask(new SecondsTimerTask()); timerThread.AddTask(new MinuteTimerTask()); timerThread.AddTask(new CountTimerTask()); Console.ReadLine(); } }
运行结果:
到此我们的定时器线程执行器已经完成,满足我们需要做到定时更新状态,合作检查数据等应用场景!
不知道对你有没有帮助呢?
请不了吝啬你的小手,给予一个评论吧,帮助到你了请给与鼓励,如果有不足之处还请多多指教!
C# 线程系列三 定时器线程的更多相关文章
- 线程系列08,实现线程锁的各种方式,使用lock,Montor,Mutex,Semaphore以及线程死锁
当涉及到多线程共享数据,需要数据同步的时候,就可以考虑使用线程锁了.本篇体验线程锁的各种用法以及线程死锁.主要包括: ※ 使用lock处理数据同步※ 使用Monitor.Enter和Monitor.E ...
- 【java线程系列】java线程系列之java线程池详解
一线程池的概念及为何需要线程池: 我们知道当我们自己创建一个线程时如果该线程执行完任务后就进入死亡状态,这样如果我们需要在次使用一个线程时得重新创建一个线程,但是线程的创建是要付出一定的代价的,如果在 ...
- 【java线程系列】java线程系列之线程间的交互wait()/notify()/notifyAll()及生产者与消费者模型
关于线程,博主写过java线程详解基本上把java线程的基础知识都讲解到位了,但是那还远远不够,多线程的存在就是为了让多个线程去协作来完成某一具体任务,比如生产者与消费者模型,因此了解线程间的协作是非 ...
- pThreads线程(三) 线程同步--条件变量
条件变量(Condition Variables) 参考资料:http://game-lab.org/posts/posix-thread-cn/#5.1 条件变量是什么? 条件变量为我们提供了另一种 ...
- java线程系列之三(线程协作)
本文来自:高爽|Coder,原文地址:http://blog.csdn.net/ghsau/article/details/7433673,转载请注明. 上一篇讲述了线程的互斥(同步),但是在很多情况 ...
- java多线程与线程并发三:线程同步通信
本文章内容整理自:张孝祥_Java多线程与并发库高级应用视频教程. 有些时候,线程间需要传递消息,比如下面这道面试题: 子线程循环10次,然后主线程循环100次,然后又回到子线程循环50次,然后再回到 ...
- Java多线程系列三——实现线程同步的方法
两种实现线程同步的方法 方法 特性 synchronized 不需要显式地加解锁,易实现 ReentrantLock 需要显式地加解锁,灵活性更好,性能更优秀,结合Condition可实现多种条件锁 ...
- (Java多线程系列三)线程间通讯
Java多线程间通讯 多线程之间通讯,其实就是多个线程在操作同一个资源,但是操作的动作不同. 1.使用wait()和notify()方法在线程中通讯 需求:第一个线程写入(input)用户,另一个线程 ...
- 死磕 java线程系列之创建线程的8种方式
(手机横屏看源码更方便) 问题 (1)创建线程有哪几种方式? (2)它们分别有什么运用场景? 简介 创建线程,是多线程编程中最基本的操作,彤哥总结了一下,大概有8种创建线程的方式,你知道吗? 继承Th ...
随机推荐
- [ASE][Daily Scrum]12.12
好久没有写daliy scrum了…… 目前看,我们的无限地图,AI以及计分都差不多成型了,不过还有很多bug在调整当中 今天要做的是 Zhao 调通分数&聊天服务器 Yiming Shili ...
- centos 安装ffmpeg
wget http://www.ffmpeg.org/releases/ffmpeg-3.1.tar.gz tar -zxvf ffmpeg-3.1.tar.gz cd ffmpeg-3.1 ./co ...
- WindowsPhone技术和XNA技术
介于公司目前还没有涉及WP(WindowsPhone)项目的开发,而我本身是学习WP开发的,因此在这里稍微入门的介绍一点WP的知识. 一.简介 Windows Phone具有桌面定制.图标拖拽.滑动控 ...
- Aoite 系列(04) - 强劲的 CommandModel 开发模式(上篇)
Aoite 是一个适于任何 .Net Framework 4.0+ 项目的快速开发整体解决方案.Aoite.CommandModel 是一种开发模式,我把它成为"命令模型",这是一 ...
- webservice2
按照 当然,里面没写清楚如何配置第三方jar 结果一访问就报错:org.codehaus.xfire.transport.http.XFireConfigurableServlet 4年前就搞过ws的 ...
- 我心中的核心组件(可插拔的AOP)~消息组件~完善篇
回到目录 为什么要有本篇文章 本篇文章主要实现了RTX消息生产者,并且完成了整体的设计方式,之前在设计时消息生产者全局使用单一的生产方式,即一个项目里使用了Email就不能使用SMS,这种设计方法和实 ...
- MyBatis学习总结(三)——优化MyBatis配置文件中的配置
一.连接数据库的配置单独放在一个properties文件中 之前,我们是直接将数据库的连接配置信息写在了MyBatis的conf.xml文件中,如下: 1 <?xml version=" ...
- Atitit Immutability 和final的优点
Atitit Immutability 和final的优点 什么是 immutability? 其实细分起来有语法上的 immutable (例如 Java 里的 final 关键字), 和运行时对象 ...
- jQuery UI AutoComplete的使用
现场提出优化单,Table Mapping里关于获取数据源下所有表名的地方由于表数量过多选择不便,需添加搜索功能.原本的实现是一个Dialog ,现打算将其改为AutoComplete. 框架使用的是 ...
- C语言数组空间的初始化详解
数组空间的初始化就是为每一个标签地址赋值.按照标签逐一处理.如果我们需要为每一个内存赋值,假如有一个int a[100];我们就需要用下标为100个int类型的空间赋值.这样的工作量是非常大的,我们就 ...