C#中Forms.Timer、Timers.Timer、Threading.Timer的用法分析

本文详细分析了.NET Framework中的三种Timer:Forms.Timer(单线程计时器)、Timers.Timer(多线程计时器)和Threading.Timer(多线程计时器)。Forms.Timer基于Windows消息循环,适用于UI操作,但可能导致UI假死;Timers.Timer使用Elapsed事件,多线程执行,避免UI假死;Threading.Timer则通过回调方法实现,由线程池提供服务,适合非UI线程操作。

摘要生成于 C知道 ,由 DeepSeek-R1 满血版支持, 前往体验 >

一、在.NET Framework里面提供了三种Timer(计时器)

① System.Windows.Forms.Timer(单线程计时器)

② System.Timers.Timer(多线程计时器)

③ System.Threading.Timer(多线程计时器)

④System.Threading.Thread(多线程)

二、System.Windows.Forms.Timer(单线程计时器)

2.1、说明

①基于Windows消息循环,用事件方式触发,在界面线程执行;是使用得比较多的Timer,Timer Start之后定时(按设定的Interval)调用挂接在Tick事件上的EvnetHandler。在这种Timer的EventHandler中可 以直接获取和修改UI元素而不会出现问题--因为这种Timer实际上就是在UI线程自身上进行调用的。

②它是一个基于Form的计时器。
③创建之后,你可以使用Interval设置Tick之间的跨度,用委托(delegate)hook Tick事件。
④调用Start和Stop方法,开始和停止;设置Enabled属性是暂停和重启。
⑤完全基于UI线程,因此部分UI相关的操作会在这个计时器内进行。
⑥长时间的UI操作可能导致部分Tick丢失。

⑦Timer 用于以用户定义的事件(Tick)间隔触发事件。Windows 计时器是为【单线程】环境设计的,其中UI 线程用于执行处理。它要求用户代码有一个可用的 UI 消息泵,而且总是在同一个线程中操作,或者将调用封送到另一个线程。

⑧Windows 将这个定时器与调用线程关联(UI线程)。当定时器触发时,Windows 把一个定时器消息插入到线程消息队列中。调用线程执行一个消息泵提取消息,然后发送到回调方法中(这里的myTimer_Tick方法)。而这些都是单线程进行了,所以在执行回调方法时UI会假死。所以使用这个控件不宜执行【计算受限】或【IO受限】的代码,因为这样容易导致界面假死,而应该使用多线程调用的 Timer。另外要注意的是这个控件时间精度不高,精度限定为55 毫秒。

2.2、示例如下:

using System;
using System.Collections.Generic;
using System.ComponentModel;
using System.Data;
using System.Drawing;
using System.Linq;
using System.Text;
using System.Threading;
using System.Threading.Tasks;
using System.Windows.Forms;

namespace TestTimer
{
    public partial class Form1 : Form
    {
        #region   基础参数
        private int num = 0;

        #endregion

        public Form1()
        {
            InitializeComponent();
        }

      
        //计时器执行方法
        private void Timer_Form_Tick(object sender, EventArgs e)
        {
            label1.Text += (++num).ToString();
            Thread.Sleep(3000);
        }

        //启动
        private void button1_Click(object sender, EventArgs e)
        {
            Timer_Form.Start();
        }

        //暂停
        private void button2_Click(object sender, EventArgs e)
        {
            Timer_Form.Enabled = false;
        }

        //重启
        private void button4_Click(object sender, EventArgs e)
        {
            Timer_Form.Enabled = true;
        }

        //终止
        private void button3_Click(object sender, EventArgs e)
        {
            Timer_Form.Stop();
        }

    }//Class_end
}

 2.3、示例解析

①上面这个是一个很简单的功能,在Form窗体上拖了一个System.Windows.Forms.Timer控件名字为Form_Timer,在属性窗中把Enable属性设置为Ture,Interval是定时器的间隔时间双击这个控件就可以看到 Form_Timer_Tick方法。在这个方法中,我们让她不停的加一个数字并显示在窗体上,2个按钮提供了对计时器的控制功能。
执行的时候你去点击其他窗体在回来,你会发现我们的窗体失去响应了。因为我们这里使用Thread.Sleep(3000);让当前线程挂起,而UI失去相应,说明了这里执行时候采用的是单线程。也就是执行定时器的线程就是UI线程。
Timer 用于以用户定义的事件间隔触发事件。Windows 计时器是为单线程环境设计的,其中,UI 线程用于执行处理。它要求用户代码有一个可用的 UI 消息泵,而且总是在同一个线程中操作,或者将调用封送到另一个线程。
在Timer内部定义的了一个Tick事件,我们前面双击这个控件时实际是增加了一行代码

this.Form_Timer.Tick += new System.EventHandler(this.Form_Timer_Tick);

然后Windows将这个定时器与调用线程关联(UI线程)。当定时器触发时,Windows把一个定时器消息插入到线程消息队列中。调用线程执行一个消息泵提取消息,然后发送到回调方法中(这里的Form_Timer_Tick方法)。而这些都是单线程进行了,所以在执行回调方法时UI会假死。所以使用这个控件不宜执行计算受限或IO受限的代码,因为这样容易导致界面假死,而应该使用多线程调用的Timer。另外要注意的是这个控件时间精度不高,精度限定为 55 毫秒。

三、 System.Timers.Timer(多线程计时器)

3.1、说明

①用的不是Tick事件,而是Elapsed事件
② 和System.Windows.Forms.Timer一样,用Start和Stop方法
③AutoReset属性决定计时器是不是要发起一次事件然后停止,还是进入开始/等待的循环。System.Windows.Forms.Timer没有这个属性
④设置对于UI控件的同步对象(synchronizing object),对控件的UI线程发起事件

3.2、示例如下

using System;
using System.Collections.Generic;
using System.ComponentModel;
using System.Data;
using System.Drawing;
using System.Linq;
using System.Text;
using System.Threading;
using System.Threading.Tasks;
using System.Windows.Forms;

namespace TestTimer
{
    public partial class Form1 : Form
    {
        #region   基础参数
        private int num = 0;
        DateTime time1 = new DateTime();
        DateTime time2 = new DateTime();

        //定义Timer
        System.Timers.Timer _Timer = new System.Timers.Timer();

        #endregion

        public Form1()
        {
            InitializeComponent();
        }

      

        void Timer_Elapsed(object sender,System.Timers.ElapsedEventArgs e)
        {
            //添加上这一句才不会出现“线程间操作无效: 从不是创建控件“label1”的线程访问它”
            Control.CheckForIllegalCrossThreadCalls = false;
            label1.Text += (++num).ToString();
            Thread.Sleep(3000);
        }

        //启动
        private void button1_Click(object sender, EventArgs e)
        {
            //手动设置Timer,开始执行
            _Timer.Interval = 20;
            _Timer.Enabled = true;
            _Timer.Elapsed += new System.Timers.ElapsedEventHandler(Timer_Elapsed);
            time1 = DateTime.Now;

            _Timer.Start();
           
        }

        //暂停
        private void button2_Click(object sender, EventArgs e)
        {
            _Timer.Enabled = false;
            time1 = DateTime.Now;
        }

        //重启
        private void button4_Click(object sender, EventArgs e)
        {
            _Timer.Enabled = true;
            time1 = DateTime.Now;
        }

        //终止
        private void button3_Click(object sender, EventArgs e)
        {
            _Timer.Enabled = false;
            time2 = DateTime.Now;
            _Timer.Stop();
            MessageBox.Show("时间为:"+(time2-time1).ToString());
        }

    }//Class_end
}

3.3、示例解析

 ①直接创建了一个【 System.Timers.Timer】计时器变量来管理操作,无需进行桌面的拖拽操作;

②多线程执行的方法是通过【 _Timer.Elapsed += new System.Timers.ElapsedEventHandler(Timer_Elapsed);】

③真正调用UI执行的方法是:

 void Timer_Elapsed(object sender,System.Timers.ElapsedEventArgs e)
        {
            //添加上这一句才不会出现“线程间操作无效: 从不是创建控件“label1”的线程访问它”
            Control.CheckForIllegalCrossThreadCalls = false;
            label1.Text += (++num).ToString();
            Thread.Sleep(3000);
        }

④不会造成UI假死情况,可以正常多线程执行,但是需要不出错需要使用【  Control.CheckForIllegalCrossThreadCalls = false;】 

四、System.Threading.Timer(多线程计时器)

4.1、说明

①以一种回调方法的方式实现,而不是通过事件来实现的。

②是一个简单的轻量计时器,它使用回调方法并由线程池线程提供服务。

4.2、示例

using System;
using System.Collections.Generic;
using System.ComponentModel;
using System.Data;
using System.Drawing;
using System.Linq;
using System.Text;
using System.Threading;
using System.Threading.Tasks;
using System.Windows.Forms;

namespace TestTimer
{
    public partial class Form1 : Form
    {
        #region   基础参数
        private int num = 0;
        DateTime time1 = new DateTime();
        DateTime time2 = new DateTime();

        //定义线程Timer
        System.Threading.Timer _ThreadTimer;

        #endregion

        public Form1()
        {
            InitializeComponent();
        }

      

        //启动
        private void button1_Click(object sender, EventArgs e)
        {
            //启动
            _ThreadTimer = new System.Threading.Timer(Thread_Timer_Method,null,0,20);
            time1 = DateTime.Now;
           
        }

        void Thread_Timer_Method(object obj)
        {
            Control.CheckForIllegalCrossThreadCalls = false;
            label1.Text += (++num).ToString();
            System.Threading.Thread.Sleep(3000);
        }

        //暂停
        private void button2_Click(object sender, EventArgs e)
        {
            _ThreadTimer.Dispose();
            time2 = DateTime.Now;
            MessageBox.Show("时间为:" + (time2 - time1).ToString());
        }

        //重启
        private void button4_Click(object sender, EventArgs e)
        {
            //启动
            _ThreadTimer = new System.Threading.Timer(Thread_Timer_Method, null, 0, 20);
            time1 = DateTime.Now;
        }

        //终止
        private void button3_Click(object sender, EventArgs e)
        {
            _ThreadTimer.Dispose();
            time2 = DateTime.Now;
            MessageBox.Show("时间为:"+(time2-time1).ToString());
        }

    }//Class_end
}

4.3、示例解析

①用Threading.Timer时的方法,和前面就不太相同了,所以的参数全部在构造函数中进行了设置,而且可以设置启动时间。而且没有提供start和stop方法来控制计时器。而且是以一种回调方法的方式实现,而不是通过事件来实现的。他们之间还是有区别的。

②我们只有销毁掉对象来停止他。当你运行时,你会发现他和前面的Timers.Timer一样,是多线程的,主要表现在不会假死,调试运行报错。但跟让你奇怪的是,我们的代码竟然无法让她停止下来。调用了Dispose方法没有用。问题在那?然后有进行了测试,修改了间隔时间为100,200,500,1000,3000,4000。这几种情况。发现当间隔为500ms以上是基本马上就停止了。而间隔时间相对执行时间越短,继续执行的时间越长。这应该是在间隔时间小于执行时间时多个线程运行造成的。因为所有的线程不是同时停止的。间隔越短,线程越多,所以执行次数越多。

③System.Threading.Timer 是一个简单的轻量计时器,它使用回调方法并由线程池线程提供服务。不建议将其用于 Windows 窗体,因为其回调不在用户界面线程上进行。

五、System.Threading.Thread(多线程)

示例:

using System;
using System.Collections.Generic;
using System.ComponentModel;
using System.Data;
using System.Drawing;
using System.Linq;
using System.Text;
using System.Threading;
using System.Threading.Tasks;
using System.Windows.Forms;

namespace TestTimer
{
    public partial class Form1 : Form
    {
        #region   基础参数
        private delegate void ReflushInfo();//定义委托

        private int num = 0;

        //定义线程
        System.Threading.Thread _Thread;
        //线程启动开关
        private bool _Start = false;

        #endregion

        public Form1()
        {
            InitializeComponent();
        }

        //启动
        private void button1_Click(object sender, EventArgs e)
        {
            //启动
            _Thread = new Thread(ThreadReflush);
            _Thread.IsBackground = true;
            _Start = true;
            _Thread.Start();

        }

        //线程刷新
        private void ThreadReflush()
        {
            while (_Start)
            {
                Thread.Sleep(1000);
                ThreadMethond();
            }
        }

        //线程赋值刷新界面
        private void ThreadMethond()
        {
            if (label1.InvokeRequired)
            {
                ReflushInfo _RI = new ReflushInfo(ThreadMethond);
                this.Invoke(_RI);
            }
            else
            {
                label1.Text += (++num).ToString();
            }
        }

        //暂停
        private void button2_Click(object sender, EventArgs e)
        {
            _Start = false;
            _Thread.Abort();


        }

        //重启
        private void button4_Click(object sender, EventArgs e)
        {
            _Start = true;
            //启动
            _Thread = new Thread(ThreadReflush);
            _Thread.IsBackground = true;
            _Start = true;
            _Thread.Start();

        }

        //终止
        private void button3_Click(object sender, EventArgs e)
        {
            _Thread.Abort();
        }

    }//Class_end
}

 

 


 

 

 

 

 

评论 2
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值