其他分享
首页 > 其他分享> > .Net中的计时器Timer你真的会用吗?

.Net中的计时器Timer你真的会用吗?

作者:互联网

一、Timer存在的问题

注意:下面演示的Timer都是指的System.Threading的Timer类。

先看以下代码:

    //实例化定时器,并以1000毫秒/次的频率执行
    Timer timer = new(Test, null, 0, 1000);

    //第1个参数指“在调用指定的回调方法之前延迟的时间量”
    //第2个参数指“回调方法的调用之间的时间间隔”
    timer.Change(0, 0);

    //定时执行的业务
    void Test(object? state)
    {
        //获取当前的线程ID
        int id = Thread.CurrentThread.ManagedThreadId;

        //获取一个随机数
        Random random = new Random();
        int roundId = random.Next(1, 10000);

        Console.WriteLine($"{DateTime.Now} 线程ID = {id}_{roundId} 开始执行");

        //模拟耗时的操作
        Thread.Sleep(3000);

        Console.WriteLine($"{DateTime.Now} 线程ID = {id}_{roundId} 结束执行");
    }

解释一下上面的代码:
创建一个定时器timer对象,以1000毫秒的频率循环执行回调方法Test,在方法Test中模拟一个耗时的操作,每次会耗费3000毫秒。为了区分每次执行,通过线程ID和一个随机数作为唯一ID。
程序执行结果如下:

通过上图可以看出,第一次执行Test回调方法还没结束,就开始执行了第2次定时任务,在很多业务场景中,这是不允许的,这会导致很多不必要的麻烦,这也是在我们使用Timer的时候,需要重点关注的。

二、正确的做法

步骤:
1、在创建定时器Timer时,指定Change()的第2个参数为Timeout.Infinite,这样,定时器就只会出发一次。
2、在回调方法中,再次调用Change(),同样需要指定参数为Timeout.Infinite。

Timer _timer = null;

//实例化定时器,并以1000毫秒/次的频率执行
_timer = new(Test, null, 0, 1000);

//第1个参数指返回前timer,不需要等待
//第2个参数指不“超时时间无穷大”,如果第一个循环任务一直没完成,一直等待下去
_timer.Change(0, Timeout.Infinite);

void Test(object? state)
{
    //获取当前的线程ID
    int id = Thread.CurrentThread.ManagedThreadId;

    //获取一个随机数
    Random random = new Random();
    int roundId = random.Next(1, 10000);

    Console.WriteLine($"线程ID = {id} 开始执行,{roundId}");

    //模拟耗时的操作
    Thread.Sleep(3000);

    Console.WriteLine($"线程ID = {id} 结束执行,{roundId}");

    //这里需要再次启动下一个定时任务
    _timer.Change(0, Timeout.Infinite);
}

执行的结果:

通过上图可以看出,每次定时任务执行完后,才会继续执行下一个定时任务。

三、Timer的释放

Timer对象垃圾回收时,它的终结代码告诉线程池取消计数器,使它不再触发。所以,在使用Timer对象时,要确定有一个变量在保持Timer对象的存活,否则对你的回调方法的调用就会停止。

四、多种类型的定时器区别

1、System.Threading的Timer类

这个就是上文讨论的定时器,也是最好的定时器,它是通过线程池去处理的,多线程的(通过上图可以看出,每次的线程ID都不一样),推荐使用。

2、System.Windows.Forms的Timer类

单线程的定时器,不会存在多线程并发的问题。

3、System.Windows.Threading的DispatcherTimer类

这个类是System.Windows.Forms的Timer类在Silverlight和WPF应用程序中的等价物。

4、Windows.UI.Xaml的DispatcherTimer类

这个类是System.Windows.Forms的Timer类在Windows.Store应用程序中的等价物。

5、System.Timers的Timer类

这个定时器本质上是System.Threading的Timer类的扩展类,Microsoft使它在设计器(Winform等项目)中更容易使用。
但是,这个类是好多年前,Microsoft还没有理清线程处理和计时器的时候添加到FCL中的,所以存在一定的缺陷(我也没遇到过)。
所以,强烈建议不要使用这个Timer,推荐使用System.Threading.Timer类。除非,你真的必须要用它。

标签:定时器,System,Timer,线程,timer,计时器,Net,ID
来源: https://www.cnblogs.com/myblog2021/p/16683796.html