现在,我们简单地谈一谈类库和线程同步。Microsoft的Framework Class Library(FCL) 保证所有静态方法都是线程安全的。这意味着假如两个线程同时调用一个静态方法,不会由数据被损坏。FLC必须在内部做到这一点,因为开发不同程序集的多个公司不可能事先协商好使用一个锁来仲裁对资源的访问。Console类包含一个静态字段,类的许多方法都要获取和释放这个字段上的锁,以确保一次只有一个线程访问控制台。
要郑重声明的是,使一个方法线程安全,并不是说它一定要在内部获取一个线程同步锁。一个线程安全的方法意味着在两个线程试图同时访问数据时,数据不会被破坏。System.Math类的一个静态Max方法,它是像下面这样实现的:
public static Int32 Max(Int32 val1, Int32 val2){
return (val1 < val2) ? val2: val1;
}
这个方法是线程安全的,即使它没有获取任何锁。由于Int32是值类型,所以传给Max两个Int32值复制到方法内部。多个线程可以同时调用Max方法,每个线程处理的都是它自己的数据,线程之间互不干扰。
另一方面,FCL不保证实例方法是线程安全的。因为假如全部添加锁定,会造成性能的巨大损失。另外,假如每个实例方法都需要获取和释放一个锁,事实上会造成最终在任何给定的时刻,你的应用程序只有一个线程在运行,这对性能的影响是显而易见的。如前所述,一个线程构造一个对象时,只有这个线程才拥有对象引用,其他线程都不能访问拿个对象,所以在调用实例方法时无需线程同步。然后,如果线程随后公开了这个对象引用——把它放到一个静态字段中,把它作为状态实参传给ThreadPool.QueueUserWorkItem或者传给一个Task_那么在多个线程可能同时进行非只读访问的前提下,就需要线程同步。
建议你的自己的类库也遵循FCL的这个模式;也就是说,使自己的所有静态方法都线程安全,使所有实例方法都非线程安全。这个模式有一点要注意:如果实例方法的目的是协调线程,则实例方法应该是线程安全的。例如,一个线程可能调用CancellationTokenSource的Cancel方法取消一个操作,另一个线程通过查询CancellationToken的IsCancellationRequested属性,检测到它应该停止它正在做的事情。这两个实例成员内部有一些特殊的线程同步代码,可确保两个线程的协作正常运行。