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
免责声明:本站发布的内容(图片、视频和文字)以原创、转载和分享为主,文章观点不代表本网站立场,如果涉及侵权请联系站长邮箱:is@yisu.com进行举报,并提供相关证据,一经查实,将立刻删除涉嫌侵权内容。