Lock 互斥锁
定义:lock 确保当一个线程位于代码的临界区时,另一个线程不进入临界区。如果其他线程试图进入锁定的代码,则它将一直等待(即被阻止),直到该对象被释放。
Monitor 方法是静态的,不需要生成Monitor 类的实例就可以直接调用它们。在.NET Framework 中,每个对象都有一个与之关联的锁,对象可以得到并释放它以便于在任意时间只有一个线程可以访问对象实例变量和方法。
Lock语句可以说就是通过Monitor.Enter()和Monitor.Exit()实现的。
当Lock(lockInstance){}结构开始执行时调用Monitor.Enter(lockInstance)锁定lockInstance临界区,当该结构执行结束,调用monitor.Exit(lockInstance)释放lockInstance临界区。
原理:对于任何一个对象来说,它在内存中的第一部分放置的是所有方法的地址,第二部分放着一个索引,这个索引指向CLR中的SyncBlock Cache区域中的一个SyncBlock。当你执行Monitor.Enter(Object)时,如果object的索引值为负数,就从SyncBlock Cache中选取一个SyncBlock,将其地址放在object的索引中。这样就完成了以object为标志的锁定,其他的线程想再次进行Monitor.Enter(object)操作,将获得object的已经为正值的索引,然后就等待。直到索引变为负数,即调用Monitor.Exit(object)将索引变为负数,等待的线程开始执行
注意:
1.lock不能锁定空值,但Null是不需要被释放的。
2.lock不能锁定string类型,虽然它也是引用类型的。因为字符串类型被CLR“暂留”。即整个程序中任何给定字符串都只有一个实例,具有相同内容的字符串都代表着同一个实例。因此,只要在应用程序进程中的任何位置处具有相同内容的字符串上放置了锁,就将锁定应用程序中与该字符串具有相同内容的字符串。因此,最好锁定不会被暂留的私有或受保护成员。
当我们使用线程的时候,效率最高的方式当然是异步,即各个线程同时运行,其间不相互依赖和等待。但当不同的线程都需要访问某个资源的时候,就需要同步机制了,也就是说当对同一个资源进行读写的时候,我们要使该资源在同一时刻只能被一个线程操作,以确保每个操作都是有效即时的,也即保证其操作的原子性。lock是C#中最常用的同步方式,格式为lock(objectA){codeB} 。
lock(objectA){codeB} 看似简单,实际上有三个意思,这对于适当地使用它至关重要:
1. objectA被lock了吗?没有则由我来lock,否则一直等待,直至objectA被释放。
2. lock以后在执行codeB的期间其他线程不能调用codeB,也不能使用objectA。
3. 执行完codeB之后释放objectA,并且codeB可以被其他线程访问。
private static readonly object SequenceLock = new object(); public string XMethod(string params) { // ... lock (SequenceLock) { //互斥内容 //... } }