C#Monitor类的使用

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


本文名称:C#Monitor类的使用
本文链接:http://myzitong.com/article/jecoji.html