上一篇文章我们讲诉了自定义线程执行器和任务处理器

我们继续来讲解自定义线程的定时执行器,我们在很多场景下需要做到某些状态或者数据进行更新,如果事情很多很杂,很时候时候会创建很多不同的定时器那么势必会照成系统的消耗和性能低下的问题!今天我们来解决这一问题。

首先我们创建定时任务执行器基类

 /// <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# 线程系列三 定时器线程的更多相关文章

  1. 线程系列08,实现线程锁的各种方式,使用lock,Montor,Mutex,Semaphore以及线程死锁

    当涉及到多线程共享数据,需要数据同步的时候,就可以考虑使用线程锁了.本篇体验线程锁的各种用法以及线程死锁.主要包括: ※ 使用lock处理数据同步※ 使用Monitor.Enter和Monitor.E ...

  2. 【java线程系列】java线程系列之java线程池详解

    一线程池的概念及为何需要线程池: 我们知道当我们自己创建一个线程时如果该线程执行完任务后就进入死亡状态,这样如果我们需要在次使用一个线程时得重新创建一个线程,但是线程的创建是要付出一定的代价的,如果在 ...

  3. 【java线程系列】java线程系列之线程间的交互wait()/notify()/notifyAll()及生产者与消费者模型

    关于线程,博主写过java线程详解基本上把java线程的基础知识都讲解到位了,但是那还远远不够,多线程的存在就是为了让多个线程去协作来完成某一具体任务,比如生产者与消费者模型,因此了解线程间的协作是非 ...

  4. pThreads线程(三) 线程同步--条件变量

    条件变量(Condition Variables) 参考资料:http://game-lab.org/posts/posix-thread-cn/#5.1 条件变量是什么? 条件变量为我们提供了另一种 ...

  5. java线程系列之三(线程协作)

    本文来自:高爽|Coder,原文地址:http://blog.csdn.net/ghsau/article/details/7433673,转载请注明. 上一篇讲述了线程的互斥(同步),但是在很多情况 ...

  6. java多线程与线程并发三:线程同步通信

    本文章内容整理自:张孝祥_Java多线程与并发库高级应用视频教程. 有些时候,线程间需要传递消息,比如下面这道面试题: 子线程循环10次,然后主线程循环100次,然后又回到子线程循环50次,然后再回到 ...

  7. Java多线程系列三——实现线程同步的方法

    两种实现线程同步的方法 方法 特性 synchronized 不需要显式地加解锁,易实现 ReentrantLock 需要显式地加解锁,灵活性更好,性能更优秀,结合Condition可实现多种条件锁 ...

  8. (Java多线程系列三)线程间通讯

    Java多线程间通讯 多线程之间通讯,其实就是多个线程在操作同一个资源,但是操作的动作不同. 1.使用wait()和notify()方法在线程中通讯 需求:第一个线程写入(input)用户,另一个线程 ...

  9. 死磕 java线程系列之创建线程的8种方式

    (手机横屏看源码更方便) 问题 (1)创建线程有哪几种方式? (2)它们分别有什么运用场景? 简介 创建线程,是多线程编程中最基本的操作,彤哥总结了一下,大概有8种创建线程的方式,你知道吗? 继承Th ...

随机推荐

  1. ajax跟取后台 josn 之 josn理解

    json是一种轻量级的数据交换格式,是 JavaScript 原生格式,是理想的数据交换格式. 1.json对象json对象以“{”开始 , 以“}”结束,每个“名称”后跟一个“:”(冒号),‘名:值 ...

  2. 【C语言学习】《C Primer Plus》第8章 字符输入/输出和输入确认

    学习总结 1.缓冲区分为完全缓冲区(fully buffered)I/O和行缓冲区(line-buffered)I/O.对完全缓冲输入来说,当缓冲区满的时候会被清空(缓冲区内容发送至其目的地).这类型 ...

  3. openwrt-智能路由器hack技术(2)---"网路信息监控和窃取"

    openwrt-智能路由器hack技术(2)---"网路信息监控和窃取" 1   导读 PS:之前写的一个文章,现在发现结构内容排版不是太好,导致阅读体验太差,影响传播和SEO,所 ...

  4. 像素图的实时光照 Lighting on Pixel Art

    去年有这样一个工具,We got one toolkit last year. 他有什么功能呢?What is its function? 让你画出各个方向的照明图 That you can draw ...

  5. [stm32] 一个简单的stm32vet6驱动2.4寸240X320的8位并口tft屏DEMO

    书接上文: 最近在研究用低速.低RAM的单片机来驱动小LCD或TFT彩屏实现动画效果 首先我用一个16MHz晶振的m0内核的8位单片机nRF51822尝试驱动一个1.77寸的4线SPI屏(128X16 ...

  6. 创业6&7

    周末两天泡咖啡店. 起不来,只好下午去. 周六5点到9点. 周日3点到12点. 1)整理直播课程讲义.完成50%. 2)修改GMTC演讲稿.完成. 招行的单子还是拒了,目前还没准备好高可用的App服务 ...

  7. Java中反射的理解

    反射 一.什么是反射 Java 反射是Java语言的一个很重要的特征,它使得Java具体了"动态性". 反射用在 Java 身上指的是我们可以于运行时加载.探知.使用编译期间完全未 ...

  8. Atitit 图像处理30大经典算法attilax总结

    Atitit 图像处理30大经典算法attilax总结 1. 识别模糊图片算法2 2. 相似度识别算法(ahash,phash,dhash)2 3. 分辨率太小图片2 4. 横条薯条广告2 5. 图像 ...

  9. Android 图片文件操作、屏幕相关、.9图片的理解

     一:Android图片操作 1.存储bitmap到本地文件系统 public static void bitmapToFile(Bitmap bitmap, String uri) { if(!ex ...

  10. 每天一个linux命令(11):nl命令

    nl命令在linux系统中用来计算文件中行号.nl 可以将输出的文件内容自动的加上行号!其默认的结果与 cat -n 有点不太一样, nl 可以将行号做比较多的显示设计,包括位数与是否自动补齐 0 等 ...