8.1定时器
若要长期定时进行一些工作,比如像邮箱更新,实时收听信息等等,可以利用定时器Timer进行操作。
在System.Threading命名空间中存在Timer类与对应的TimerCallback委托,它可以在后台线程中执行一些长期的定时操作,使主线程不受干扰。Timer类中最常用的构造函数为 public Timer( timerCallback , object , int , int )timerCallback委托可以绑定执行方法,执行方法必须返回void,它可以是无参数方法,也可以带一个object参数的方法。第二个参数是为 timerCallback 委托输入的参数对象。第三个参数是开始执行前等待的时间。第四个参数是每次执行之间的等待时间。开发实例
1 class Program 2 { 3 static void Main(string[] args) 4 { 5 ThreadPool.SetMaxThreads(1000, 1000); 6 7 TimerCallback callback = new TimerCallback(ThreadPoolMessage); 8 Timer t = new Timer(callback,"Hello Jack! ", 0, 1000); 9 Console.ReadKey(); 10 } 11 12 //显示线程池现状 13 static void ThreadPoolMessage(object data) 14 { 15 int a, b; 16 ThreadPool.GetAvailableThreads(out a, out b); 17 string message = string.Format("{0}\n CurrentThreadId is:{1}\n" + 18 " CurrentThread IsBackground:{2}\n" + 19 " WorkerThreads is:{3}\n CompletionPortThreads is:{4}\n", 20 data + "Time now is " + DateTime.Now.ToLongTimeString(), 21 Thread.CurrentThread.ManagedThreadId, 22 Thread.CurrentThread.IsBackground.ToString(), 23 a.ToString(), b.ToString()); 24 Console.WriteLine(message); 25 } 26 }
注意观察运行结果,每次调用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提倡的锁定用法。
1 class Control 2 { 3 private object obj=new object(); 4 5 public void Method() 6 { 7 lock(obj) 8 {.......} 9 } 10 }
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并返回递增后的新值。
1 class Example 2 { 3 private int a=1; 4 5 public void AddOne() 6 { 7 int newA=Interlocked.Increment(ref a); 8 } 9 }
Exchange可以安全地变量赋值。
1 public void SetData() 2 { 3 Interlocked.Exchange(ref a,100); 4 }
CompareExchange使用特别方便,它相当于if的用法,当a等于1时,则把100赋值给a。
1 public void CompareAndExchange() 2 { 3 Interlocked.CompareExchange(ref a,100,1); 4 }