目录
八、定时器与锁
8.1定时器
若要长期定时进行一些工作,比如像邮箱更新,实时收听信息等等,可以利用定时器Timer进行操作。
在System.Threading命名空间中存在Timer类与对应的TimerCallback委托,它可以在后台线程中执行一些长期的定时操作,使主线程不受干扰。
Timer类中最常用的构造函数为 public Timer( timerCallback , object , int , int )
timerCallback委托可以绑定执行方法,执行方法必须返回void,它可以是无参数方法,也可以带一个object参数的方法。
第二个参数是为 timerCallback 委托输入的参数对象。
第三个参数是开始执行前等待的时间。
第四个参数是每次执行之间的等待时间。
开发实例
class Program { static void Main(string[] args) { ThreadPool.SetMaxThreads(1000, 1000); TimerCallback callback = new TimerCallback(ThreadPoolMessage); Timer t = new Timer(callback,"Hello Jack! ", 0, 1000); Console.ReadKey(); } //显示线程池现状
static void ThreadPoolMessage(object data) { int a, b; ThreadPool.GetAvailableThreads(out a, out b); string message = string.Format("{0}\n CurrentThreadId is:{1}\n" + " CurrentThread IsBackground:{2}\n" + " WorkerThreads is:{3}\n CompletionPortThreads is:{4}\n", data + "Time now is " + DateTime.Now.ToLongTimeString(), Thread.CurrentThread.ManagedThreadId, Thread.CurrentThread.IsBackground.ToString(), a.ToString(), b.ToString()); Console.WriteLine(message); } }
注意观察运行结果,每次调用Timer绑定的方法时不一定是使用同一线程,但线程都会是来自工作者线程的后台线程。
8.2 锁
在使用多线程开发时,存在一定的共用数据,为了避免多线程同时操作同一数据,.NET提供了lock、Monitor、Interlocked等多个锁定数据的方式。
8.2.1 lock
lock的使用比较简单,如果需要锁定某个对象时,可以直接使用lock(this)的方式。
1 private void Method() 2 { 3 lock(this) 4 { 5 //在此进行的操作能保证在同一时间内只有一个线程对此对象操作
6 } 7 }
如果操作只锁定某段代码,可以事先建立一个object对象,并对此对象进行操作锁定,这也是.net提倡的锁定用法。
class Control { private object obj=new object(); public void Method() { lock(obj) {.......} } }
8.2.2 Montior
Montior存在于System.Thread命名空间内,相比lock,Montior使用更灵活。
它存在 Enter, Exit 两个方法,它可以对对象进行锁定与解锁,比lock使用更灵活。
1 class Control 2 { 3 private object obj=new object(); 4 5 public void Method() 6 { 7 Monitor.Enter(obj); 8 try 9 {......} 10 catch(Excetion ex) 11 {......} 12 finally 13 { 14 Monitor.Exit(obj); 15 } 16 } 17 } 18
使用try的方式,能确保程序不会因死锁而释放出异常!
而且在finally中释放obj对象能够确保无论是否出现死锁状态,系统都会释放obj对象。
而且Monitor中还存在Wait方法可以让线程等待一段时间,然后在完成时使用Pulse、PulseAll等方法通知等待线程。
8.2.3 Interlocked
Interlocked存在于System.Thread命名空间内,它的操作比Monitor使用更简单。
它存在CompareExchange、Decrement、Exchange、Increment等常用方法让参数在安全的情况进行数据交换。
Increment、Decrement 可以使参数安全地加1或减1并返回递增后的新值。
class Example { private int a=1; public void AddOne() { int newA=Interlocked.Increment(ref a); } }
Exchange可以安全地变量赋值。
1 public void SetData() 2 { 3 Interlocked.Exchange(ref a,100); 4 }
CompareExchange使用特别方便,它相当于if的用法,当a等于1时,则把100赋值给a。
public void CompareAndExchange() { Interlocked.CompareExchange(ref a,100,1); }
结束语
熟悉掌握多线程开发,对提高系统工作效率非常有帮助,尤其是回调方法与最近火热的并行编程更应该引起各位的重视。
在下用了较长的时间总结所过的多线程开发方式,希望本篇文章能对各位的学习研究有所帮助,当中有所错漏的地方敬请点评。