四 C# 多线程研究 Monitor和lock用法举例
这两个对象一般用于锁定一段代码,或者锁定一个对象。下面举两个例子予以说明:
1:锁定代码
Code
print(int a)中的代码被lock锁定,两个线程便只能依次访问这段代码,注意这里的类A是单例,这样是为了lock锁住的都是同一个对象。这里的lock也可以用Monitor对象来代替:
public void print(int a)
{
Monitor.Enter(_instance);
Console.WriteLine(a.ToString());
Monitor.Exit(_instance);
}
{
Monitor.Enter(_instance);
Console.WriteLine(a.ToString());
Monitor.Exit(_instance);
}
此时,一直锁定这段代码(即去掉Monitor.Exit(this)),结果将会很有趣:要么线程1一直占据这段代码的控制权,屏幕上一直输出1;要么线程2一直占据,一直输出2。由此可见:在单例模式下,不同线程中创建的不同对象,是可以通过在单例对象内部锁定一个函数来达到资源安全共享的目的。
Monitor只有在多线程的情况下才使用,否则,如果只有一个线程,会报错。
2:锁定对象
如果将threadMethod1()改成如下:
static void threadMethod1()
{
A a = A.GetInstance();
lock (a)
{
while (true)
{
a.print(1);
Thread.Sleep(1000);
}
}
}
{
A a = A.GetInstance();
lock (a)
{
while (true)
{
a.print(1);
Thread.Sleep(1000);
}
}
}
此时,屏幕上并不会一直只打印1,而是1和2几乎一起打印(print()方法中不加任何锁)。这是因为在线程1中锁定的a对象,和线程2中的a对象的指向不相同,因此线程1即使锁定了a对象,也无法阻挡线程2访问print()方法。如果要线程1一直占据对a的控制权,只能全局定义一个a对象,让线程1和线程2共享这个对象,此时线程1的锁才有意义。
由此可见,如果两个线程在外部锁定一个对象,则这两个线程中的对象必须是同一个对象,此时可以在主线程中声明一个全局对象让多线程共享。
总之,通过上面的实验,可以看出:在多线程中,要想锁定一段代码,必须使得调用方在调用对象的该段代码所在的方法时,两个线程中的对象必须是同一个对象。在外部锁定一个对象时,也必须保证两个线程中所锁定的对象是同一个对象,否则,锁将失去意义。通过单例模式或者全局声明对象,可以有效实现资源共享。