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 ...
随机推荐
- 使用 CXF 做 webservice 简单例子
Apache CXF 是一个开放源代码框架,提供了用于方便地构建和开发 Web 服务的可靠基础架构.它允许创建高性能和可扩展的服务,您可以将这样的服务部署在 Tomcat 和基于 Spring 的轻量 ...
- Linux CentOS下如何确认MySQL服务已经启动
Linux CentOS一般做为服务器使用,因此,MySQL服务应该随开机自动启动的.正常情况下,查看开机自动启动的服务使用chkconfig命令,如下: #chkconfig --list 实际使用 ...
- MySQL2:四种MySQL存储引擎
前言 数据库存储引擎是数据库底层软件组织,数据库管理系统(DBMS)使用数据引擎进行创建.查询.更新和删除数据.不同的存储引擎提供不同的存储机制.索引技巧.锁定水平等功能,使用不同的存储引擎,还可以 ...
- [.net 面向对象编程基础] (21) 委托
[.net 面向对象编程基础] (20) 委托 上节在讲到LINQ的匿名方法中说到了委托,不过比较简单,没了解清楚没关系,这节中会详细说明委托. 1. 什么是委托? 学习委托,我想说,学会了就感觉简 ...
- 使用ACE_Get_Opt解析命令行
当我们用C++开发一些C++控制台小工具时,会需要一些用户输入的参数来决定程序如何工作和执行,而用户输入参数的方式大部分都是采用命令行参数的方式. 比如上一篇文章 玩转Windows服务系列--命令行 ...
- js实现DOM结构
/* 编写一段js脚本生成下面的DOM结构.要求使用标准的DOM方法或属性 <div id='example'> <p class='slogan'>淘,你喜欢</p&g ...
- Facebook 发布「流程」
时不时就会在面试过程中碰到有候选人问 Facebook 是否采用 Scrum 之类的敏捷方法,偶尔也会有中国的朋友问及 Facebook 上线流程.我通常会简单说几句,然后说「如果你真感兴趣的话,去搜 ...
- 如何应用Font Awesome矢量字体图标
Font Awesome 是一套专门为 Twitter Boostrap 设计的图标字体库.这套图标字体集几乎囊括了网页中可能用到的所有图标,除了包括 Twitter Boostrap 的默认图标外, ...
- [每天默写一个算法]KMP
[每天默写一个算法]KMP 作业要求:默写String的KMP算法. KMP是经典的字符串匹配算法.复杂度为O(n+m) public static class StringKMP { /// < ...
- Git学习笔记(4)——添加远程仓库,克隆远程库,以及库的推送
本文记录了远程库的连接和库的克隆和推送. 远程仓库简介 Git是分布式版本控制系统,同一个Git仓库,可以分布到不同的机器上.有一台机器有一个原始版本库,此后,别的机器可以“克隆”这个原始版本库,而且 ...