C# lock Monitor Mutex SpinLock 区别
1、Mutex 互斥锁
Mutex mut = new Mutex(); ... mut.WaitOne(); ... mut.ReleaseMutex();//释放锁
只能有一个线程 进入执行逻辑
if (mut.WaitOne(1000)) { //等待一个时间,超过时间将返回false // Simulate some work. Thread.Sleep(5000); // Release the Mutex. mut.ReleaseMutex(); } else { Console.WriteLine("{0} will not acquire the mutex", Thread.CurrentThread.Name); }
上面的实例说明,当一个线程进入执行逻辑后,如果其他线程等待超时,将不再进入执行逻辑。
2、Monitor --只能加锁 引用类型对象
Random rnd = new Random();//定义一随机数生成对象 Monitor.Enter(rnd); ... Monitor.Exit(rnd);
当锁定一个值类型,会出现什么情况呢?每个任务都将引发 SynchronizationLockException 异常。如下代码所示
int nTasks = 0; Monitor.Enter(nTasks); try { nTasks += 1; } finally { Monitor.Exit(nTasks); }
原因:Monitor会对nTasks进行装箱,退出的时候将不再是同一个引用对象,所以会抛出异常。
以上的解决方法是,使用nTasks之前先进行装箱。
int nTasks = 0; object o = nTasks; Monitor.Enter(o); try { nTasks++; } finally { Monitor.Exit(o); }
3、lock 关键字--底层由Monitor实现。
lock 关键字可确保当一个线程位于代码的临界区时,另一个线程不会进入该临界区。 如果其他线程尝试进入锁定的代码,则它将一直等待(即被阻止),直到该对象被释放。
lock 关键字在块的开始处调用 Enter,而在块的结尾处调用 Exit。 ThreadInterruptedException 引发,如果 Interrupt 中断等待输入 lock 语句的线程。
通常,应避免锁定 public 类型,否则实例将超出代码的控制范围。
常见的结构 lock (this)、lock (typeof (MyType)) 和 lock ("myLock") 违反此准则:
如果实例可以被公共访问,将出现 lock (this) 问题。
如果 MyType 可以被公共访问,将出现 lock (typeof (MyType)) 问题。
由于进程中使用同一字符串的任何其他代码都将共享同一个锁,所以出现 lock("myLock") 问题。
最佳做法是定义 private 对象来锁定, 或 private static 对象变量来保护所有实例所共有的数据。
在 lock 语句的正文不能使用 等待 关键字。
Enter指的是Monitor.Enter(获取指定对象上的排他锁。),Exit指的是Monitor.Exit(释放指定对象上的排他锁。)
所以lock底层是Monitor实现的。
private static object objlock = new object(); lock (objlock ) { //要执行的代码逻辑 }
4、SpinLock 是一种低级互斥锁,可用于等待时间非常短的方案。
如果锁住的逻辑执行时间很短,请使用spinlock,这样会获得比lock 更高的性能
SpinLock _spinlock = new SpinLock(); ... bool lockTaken = false; try { _spinlock.Enter(ref lockTaken); ...;//执行时间短的逻辑 } finally { if (lockTaken) _spinlock.Exit(false); }
在 SpinLock.Exit 调用中使用 false
。 这可提供最佳性能。true的话会启动异常跟踪
上一篇: 可重入锁ReentrantLock初探
下一篇: DistributedLock