为什么这个锁定声明不起作用?
class Program { static object test = new object(); static void Main(string[] args) { new Program().test2(); Console.ReadKey(); } public void test1() { lock (test) { Console.WriteLine("test1"); } } public void test2() { lock (test) { test1(); Console.WriteLine("test2"); } } }
上面的代码应该首先在test2()的lock语句中完成语句然后转到test1()吗? (即输出不应该是这样的吗?:test2 test1)
监视器可以重新进入同一个线程。 为避免意外死锁非常重要,如果没有这种行为,您的代码会严格冻结。
互斥体也是可重入的,信号量不是。
实施非常简单。 监视器存储两条信息。 输入它的线程的所有者Thread.ManagedId和计算输入次数的计数器。 因此,第一个锁可以进入,因为它不是拥有的,它将所有者设置为您的线程并将计数设置为1.允许第二个锁进入,因为线程ID匹配,计数增加到2.结束时第二次锁定,计数再次减少到1。 在第一个结束时,计数减少到0并重置所有者。
否。事件序列(标识表示调用堆栈或逻辑操作)是:
- 主叫test2
- test2尝试获取与测试对象关联的监视器(
lock
语句的开始)- Monitor目前尚未拥有。 成功!
- 当前线程现在“拥有”该监视器,计数为1
- test2调用test1
- test1尝试获取测试对象的监视器(
lock
语句的开始)- Monitor目前拥有…但是由当前线程。 成功!
- 当前线程仍“拥有”监视器,计数为2
- test1打印“test1”
- test1释放监视器(
lock
语句的结尾)- 当前线程仍“拥有”监视器,计数为1
- test1返回
- test1尝试获取测试对象的监视器(
- test2打印“test2”
- test2释放监视器(
lock
语句的结尾)- 监视器现在是无主的(因此另一个线程可以获取它)
- test2返回
- test2尝试获取与测试对象关联的监视器(
重要的是要注意监视器是可重入的 – 如果当前线程已经拥有监视器,那么另一次获取它的尝试只会增加计数,而不是阻塞。
如果监视器不可重入,则输出不会是“test2,test1” – 它只会是死锁。
锁定不应该在单线程场景中使用。 它的目的是用于对相同方法或对象实例的跨线程调用。
你注意到的行为是正常的。
当两个或多个线程可以同时访问资源时,您通常希望同步对资源(变量,集合等)的访问。