C#中, 通过System.Threading.Monitor类可以实现多线程中对某些代码块的同步访问,以确保数据的安全性。
object obj=new object();
Monitor在锁对象obj上会维持两个线程队列R和W以及一个引用T :
(1) T是对当前获得了obj锁的线程的引用(设此线程为CurrThread);
(2) R为就绪队列, 其上的线程已经准备好获取obj锁。当obj锁被CurrThread释放后(CurrThread可通过Monitor.Exit(obj)或 Monitor.Wait(obj)来释放其所获的obj锁)这些线程就会去竞争obj锁,获得obj锁的线程将被T引用; 线程调用Monitor.Enter(obj)或Monitor.TryEnter(obj)将会使该线程直接进入R队列。
(3) W为等待队列,其上的线程是因为调用了Monitor.Wait(obj)而进入W队列的;W上的线程不会被OS直接调度执行,也就是说它们没有准备好获取obj锁,就是说在等待队列上的线程不能去获得obj锁。当前获得obj锁的线程CurrThread调用Monitor.Pulse(obj)或Monitor.PulseAll(obj)后会使W队列中的第一个等待线程或所有等待线程被移至R队列,这时被移至R队列的这些线程就有机会被OS直接调度执行,也就是有可以去竞争obj锁。
Monitor类中的重要方法:
方法名称 | 描述 |
void Enter(object obj) | Acquires an exclusive lock on the specified object. |
void Enter(object obj, ref bool lockTaken) | Acquires an exclusive lock on the specified object, and atomically sets a value that indicates whether the lock was taken. |
void Exit(object obj) | Releases an exclusive lock on the specified object. |
void Pulse(object obj) | Notifies a thread in the waiting queue of a change in the locked object's state. |
void PulseAll(object obj) | Notifies all waiting threads of a change in the object's state. |
bool TryEnter(object obj) | Attempts to acquire an exclusive lock on the specified object. |
bool TryEnter(object obj, int millisecondsTimeout) | Attempts, for the specified number of milliseconds, to acquire an exclusive lock on the specified object. |
bool Wait(object obj) | Releases the lock on an object and blocks the current thread until it reacquires the lock. If the specified time-out interval elapses, the thread enters the ready queue. |
例子1:
private object lockObj = new object();
private void Execute()
{
Monitor.Enter(lockObj);
for (int i = 0; i < 5;i++ )
{
Console.WriteLine("Thread Name:" + Thread.CurrentThread.Name + ", Count:" + i);
Thread.Sleep(new Random().Next(5000));
}
Monitor.Exit(lockObj);
}
public void Test()
{
Thread thread1 = new Thread(new ThreadStart(Execute));
thread1.Name = "Thread1";
thread1.Start();
Thread thread2 = new Thread(new ThreadStart(Execute));
thread2.Name = "Thread2";
thread2.Start();
thread1.Join();
thread2.Join();
}
输出结果:
Thread Name:Thread1, Count:0
Thread Name:Thread1, Count:1
Thread Name:Thread1, Count:2
Thread Name:Thread1, Count:3
Thread Name:Thread1, Count:4
Thread Name:Thread2, Count:0
Thread Name:Thread2, Count:1
Thread Name:Thread2, Count:2
Thread Name:Thread2, Count:3
Thread Name:Thread2, Count:4
例子2:
private void Execute1()
{
if (Monitor.TryEnter(lockObj,1000))
{
for (int i = 0; i < 5; i++)
{
Console.WriteLine("Thread Name:" + Thread.CurrentThread.Name + ", Count:" + i);
Thread.Sleep(new Random().Next(5000));
}
Monitor.Exit(lockObj);
}
}
public void Test1()
{
Thread thread1 = new Thread(new ThreadStart(Execute1));
thread1.Name = "Thread1";
thread1.Start();
Thread thread2 = new Thread(new ThreadStart(Execute1));
thread2.Name = "Thread2";
thread2.Start();
thread1.Join();
thread2.Join();
}
输出结果:
Thread Name:Thread1, Count:0
Thread Name:Thread1, Count:1
Thread Name:Thread1, Count:2
Thread Name:Thread1, Count:3
Thread Name:Thread1, Count:4
因为Thread2尝试获取锁失败,所以没有执行锁内部的代码块。
例子3:
private Queue queue = new Queue();
public void SendThread()
{
int counter = 0;
lock (queue)
{
while (counter < 5)
{
//Wait, if the queue is busy.
Monitor.Wait(queue);
//Push one element.
queue.Enqueue(counter);
//Release the waiting thread.
Monitor.Pulse(queue);
counter++;
}
}
}
public void ConsumeThread()
{
lock (queue)
{
//Release the waiting thread.
Monitor.Pulse(queue);
//Wait in the loop, while the queue is busy.
//Exit on the time-out when the first thread stops.
while (Monitor.Wait(queue, 1000))
{
//Pop the first element.
int counter = (int)queue.Dequeue();
//Print the first element.
Console.WriteLine("Queue Value:" + counter.ToString());
//Release the waiting thread.
Monitor.Pulse(queue);
}
}
}
public void Test2()
{
Thread thread1 = new Thread(new ThreadStart(SendThread));
thread1.Name = "Thread1";
thread1.Start();
Thread thread2 = new Thread(new ThreadStart(ConsumeThread));
thread2.Name = "Thread2";
thread2.Start();
thread1.Join();
thread2.Join();
Console.WriteLine("Queue Size:" + queue.Count);
}
输出结果:
Queue Value:0
Queue Value:1
Queue Value:2
Queue Value:3
Queue Value:4
Queue Size:0
亿速云「云服务器」,即开即用、新一代英特尔至强铂金CPU、三副本存储NVMe SSD云盘,价格低至29元/月。点击查看>>
免责声明:本站发布的内容(图片、视频和文字)以原创、转载和分享为主,文章观点不代表本网站立场,如果涉及侵权请联系站长邮箱:is@yisu.com进行举报,并提供相关证据,一经查实,将立刻删除涉嫌侵权内容。