前言
1、Monitor
Monitor是一个C#中System.Threading下的静态类,它提供了用于线程同步的方法和信号量。它们用来实现进入和退出临界区,以确保在同一时间只有一个线程可以访问共享资源。它有两个重要方法 Monitor.Enter和Monitor.Exit。
使用示例:
public class MyClass
{
static readonly object lockObject = new object();
public void MonitorThead()
{
// 在 C#4.0以上版本,Monitor.Enter(_object,ref _lockTaken)
// 的重载函数获取独占锁和指定的对象,并自动设置一个值,指示是否已使用锁。
Monitor.Enter(lockObject);
try
{
int j = 0;
for (int i = 0; i < 10; i++)
{
Thread.Sleep(100);
Console.Write($"{j++},");
}
Console.WriteLine();
}
finally
{
//在 C#4.0以上版本 这里判断
//if(_lockTaken)
//{
// Monitor.Exit(lockObject);
//}
Monitor.Exit(lockObject);
}
}
}
internal class Program
{
static void Main(string[] args)
{
Thread[] Threads = new Thread[2];
for (int i = 0; i < 2; i++)
{
Threads[i] = new Thread(new ThreadStart(new MyClass().MonitorThead));
Threads[i].Name = "Name " + i;
}
foreach (Thread t in Threads)
t.Start();
//Console.WriteLine("Hello, World!");
}
}
效果:
例子中我们使用Monitor来保护lockObject,使得在同一时刻只有一个线程try中的代码。如果有其他线程尝试进入会被阻塞,直到锁被释放。
2、Lock
Lock想必经常使用多线程的程序员比较熟悉了。它是C#中的一个关键字,功能其实与Monitor类似。其实Lock就是Monitor类的语法糖,编译器会将lock关键字转换为对Monitor.Enter和Monitor.Exit的调用,让语法更加简洁。下面我们将用案例反编译后的中间语言看看它们的关系。
使用示例:
public class MyClass
{
//private object lockObject = new object(); 使用更安全
static readonly object _object = new object();
public void LockThead()
{
lock (_object)
{
int j = 0;
for (int i = 0; i < 10; i++)
{
Thread.Sleep(100);
Console.Write($"{j++},");
}
Console.WriteLine();
}
}
}
static void Main(string[] args)
{
Thread[] Threads = new Thread[2];
for (int i = 0; i < 2; i++)
{
Threads[i] = new Thread(new ThreadStart(new MyClass().LockThead));
Threads[i].Name = "Name " + i;
}
foreach (Thread t in Threads)
t.Start();
}
//欢迎关注公众号:DOTNET开发跳槽,领取海量面试题。
//加微信号xbhpnet入群交流
反编译的部分代码:
以上是反编译IL代码的部分切图,从反编译IL的结果可以看出,Lock底层也用了Monitor。Lock效果跟上面的一样。只不过代码更加简洁美观。
注意Object对象的声明方式:
//由于是私有的,每一个实例都有自己对象,所以使用更安全和稳定
private object lockObject = new object();
//static readonly 由于是静态只读,全局只用一个,相当于全局锁
static readonly object _object = new object();
本案例为了展示效果使用了static readonly object。
结语