线程一般应用于计算密集型操作,或者想达到异步效果。 创建线程,销毁线程都需要消耗资源,所以线程不是越多越好。C#提供了线程池对象,线程池的好处是线程可以重复利用,并发数也会自动控制,微软不建议用户修改最大并发数。 线程分为前端线程和后台线程,区别是:应用程序必须运行完所有的前台线程才可以退出;而对于后台线程,应用程序则可以不考虑其是否已经运行完毕而直接退出,所有的后台线程在应用程序退出时都会自动结束。C#创建的线程默认为前端线程,可以通过Thread类IsBackground来设置是否为后台线程(必须在Start方法之前设置)。 Task实际上是使用的线程池中的线程,使用起来比线程池简单方便。Parallel中使用的线程有可能是线程池中的,也可能不是。 线程同步: 对于简单的数字运算,应该使用InterLocked这种轻量级锁对象。对于文件流操作应该使用ReaderWriterLockSlim对象。 其它情况可以使用Monitor,Mutex(互斥锁)或Semaphore。 lock(obj)相当于使用Monitor对象,obj对象即临界区,一般为(new object),不可以使值类型对象,string(或单例对象),或this对象。值类型使用时会发生装箱操作,使每次产生的临界区都不一样,起不到互斥作用。string类型由于内存驻留技术,所有的“abc”实际上都是同一对象,会使得其它使用“abc”的地方可能需要长时间等待(单例对象也是一样)。this对象在外面如果被lock可能会产生死锁。 Mutex比较重量级,一般用于进程间同步。 Semaphore的好处是可以进行并发数控制。 也可以使用信号量进行复杂同步控制,值得注意的是ManualResetEvent和AutoResetEvent的区别是ManualResetEvent在调用Set方法之后,所有等待线程均继续执行,而AutoResetEvent在调用Set方法之后随即有一个线程继续执行。
|