c# 线程定时器 System.Threading.Timer的使用

作者:驰愿 时间:2022-07-08 01:28:09 

System.Threading.Timer 是由线程池调用的。

所有的Timer对象只使用了一个线程来管理。这个线程知道下一个Timer对象在什么时候到期。下一个Timer对象到期时,线程就会唤醒,在内部调用ThreadPool 的 QueueUserWorkItem,将一个工作项添加到线程池队列中,使你的回调方法得到调用。如果回调方法的执行时间很长,计时器可能(在上个回调还没有完成的时候)再次触发。这可能造成多个线程池线程同时执行你的回调方法。

参数

  • callback : 一个Object 类型参数的委托,周期调用的函数。

  • state: callback 委托调用时的参数。

  • dueTime: 定时器延时多久开始调用。单位 毫秒

  • period: 定时器每隔多久调用一次。单位 毫秒

不能使用局部变量来创建指向一个线程定时器。因为局部变量会被GC回收,导致定时器失效。
比如下面的例子:

static void Main(string[] args) {

Run();

//为了加快GC垃圾回收,不停的创建对象
           for (int i = 0; i < 10000; i++) {
               cc tmp = new cc();
               Thread.Sleep(10);
           }

Console.ReadKey();

}

static int id;

static void Run() {
           Timer timer = new Timer(DoTime, null, 500, 500);
       }

static void DoTime(object obj) {
           Console.WriteLine(id++);
       }

class cc{
           public int[] a = new int[1000];
           }

c# 线程定时器 System.Threading.Timer的使用

定时器执行4次后停止了。定时器什么时候停止取决于GC什么时候回收。如果一直没有GC的回收,那么将会一直执行下去。比如把上方创建 cc 对象的代码删除。定时器将会一直执行。

可以在Main方法中使局部变量 或者 使用全局变量来存放Timer 对象 避免 clr 把Timer 回收。

比如改成这样

static Timer timer;

static void Main(string[] args) {

timer =  new Timer(DoTime, null, 500, 500);

//为了加开GC垃圾回收,不停的创建对象
           for (int i = 0; i < 10000; i++) {
               cc tmp = new cc();
               Thread.Sleep(10);
           }

Console.ReadKey();

}

static int id;

static void DoTime(object obj) {
           Console.WriteLine(id++);
       }

如果回调方法的执行时间很长,计时器可能(在上个回调还没有完成的时候)再次触发。这可能造成多个线程池线程同时执行你的回调方法。

static Timer timer1;

static void Main(string[] args) {

timer1 = new Timer(DoTime, 1, 500, 500);

Console.ReadKey();

}

static int id;

static void DoTime(object obj) {
           int idx = id ++;
           Console.WriteLine("处理开始:" + idx + "," + Thread.CurrentThread.ManagedThreadId);
           Thread.Sleep(1200);
           Console.WriteLine("处理完毕:" + idx + "," + Thread.CurrentThread.ManagedThreadId);
       }

c# 线程定时器 System.Threading.Timer的使用

定时器第一次任务还没执行完毕,第二次,第三次回调就开始了。多个线程同时并发 DoTime 方法

解决方法

period 使用 Timeout.Infinite。这个参数将导致DoTime 只处理一次。
在回调方法中使用 Change方法来修改 dueTime,period 参数。period 继续使用 Timeout.Infinite. 使用这个方法要注意如果timer 在被Dispose了,使用Change 将会引发异常。
比如

static Timer timer1;

static void Main(string[] args) {

timer1 = new Timer(DoTime, 1, 0, Timeout.Infinite);

Console.ReadKey();

}

static int id;

static void DoTime(object obj) {
           int idx = id ++;
           Console.WriteLine("处理开始:" + idx + "," + Thread.CurrentThread.ManagedThreadId);
           Thread.Sleep(1200);
           Console.WriteLine("处理完毕:" + idx + "," + Thread.CurrentThread.ManagedThreadId);
           timer1.Change(500,Timeout.Infinite);
       }

c# 线程定时器 System.Threading.Timer的使用

使用Disponse停止定时器
如果Timer 不会再使用 则可以 使用 Dispose 方法来停止定时器。
如果定时器运行到中途。使用Dispose方法后,callback还是会执行完一个完整的生命周期,不会中途停止。并且Dispose方法不会等待 callback的这次调用完成。只是定时器下次不再调用 callback。

使用Change停止定时器
把 dueTime 参数置为-1就可以停止定时器。同样的,它不会中断在运行中的callback,只是下一次不再回调。 这个方法停止的定时器 还可以使用Change 再次利用定时器。

来源:https://blog.csdn.net/qq_27461747/article/details/105505420

标签:c#,线程定时器,System.Threading.Timer
0
投稿

猜你喜欢

  • 使用SpringMVC的@Validated注解验证的实现

    2023-09-20 19:49:55
  • Java如何优雅替换if-else语句

    2023-02-23 10:30:27
  • 详解java中float与double的区别

    2021-09-12 11:04:47
  • 两个surfaceView实现切换效果

    2021-10-04 15:18:52
  • 浅析Mybatis Plus和Mybatis的区别

    2022-12-05 18:14:18
  • SpringBoot中的main方法注入service

    2021-10-31 15:33:33
  • 深入XPath的详解以及Java示例代码分析

    2021-11-01 13:42:33
  • Java内存模型之happens-before概念详解

    2023-11-23 03:11:50
  • Java 十大排序算法之计数排序刨析

    2023-11-28 19:21:26
  • Java压缩文件工具类ZipUtil使用方法代码示例

    2022-11-26 02:21:32
  • 在IDEA使用中directory和package的操作

    2022-07-05 22:05:53
  • springboot整合kaptcha生成验证码功能

    2023-07-14 21:48:51
  • spring mvc中的@ModelAttribute注解示例介绍

    2023-10-15 07:07:06
  • C#面向对象编程之猜拳游戏实现方法

    2021-11-17 23:25:52
  • Java实现简单员工管理系统

    2021-12-13 17:51:26
  • C#双缓冲实现方法(可防止闪屏)

    2021-07-07 18:15:33
  • Hadoop运行时遇到java.io.FileNotFoundException错误的解决方法

    2021-11-04 11:19:45
  • 详解Java ES多节点任务的高效分发与收集实现

    2021-08-03 13:59:02
  • Spring Boot和Vue前后端分离项目架构的全过程

    2023-09-20 17:49:13
  • android开发仿ios的UIScrollView实例代码

    2023-08-07 01:55:20
  • asp之家 软件编程 m.aspxhome.com