C# 对象锁——Monitor

Monitor里边有一些static方法,可以用于在对象上获取同步锁,来进行一些进程同步控制操作

用法及注意点如下:

using System;
using System.Collections.Generic;
using System.Linq;
using System.Text;
using System.Threading;
using System.Threading.Tasks;

namespace myTest
{
    class Program
    {
        // 一个比较容易犯的错误
        // 使用   Monitor   锁定对象(即引用类型)而不是值类型。将值类型变量传递给   Enter   时,
        //它被装箱为对象。如果再次将相同的变量传递给   Enter,则它被装箱为一个单独对象,而且线程不会阻止。Monitor  
        //本应保护的代码未受保护。此外,将变量传递给   Exit   时,
        //也创建了另一个单独对象。因为传递给   Exit   的对象和传递给   Enter   的对象不同,Monitor   
        //将引发   SynchronizationLockException
        //这种情况最好用 Interlocked 来完成
        private static int _num = 1;
        // 装箱一下就可以了
        private static object num = _num;
        static void Main(string[] args)
        {

            Thread t1 = new Thread(new ThreadStart(addNum));
            t1.Name = "线程1";
            Thread t2 = new Thread(new ThreadStart(addNum));
            t2.Name = "线程2";
            t1.Start();
            t2.Start();
            Console.ReadLine();
        }
        //|- 拥有锁的线程 lockObj->|- 就绪队列(ready queue) |- 等待队列(wait queue)
        // 就绪队列:尝试lock对象的线程
        // 等待队列:在等待中, !!!不会主动!!!    去lock对象的线程  Monitor.wait 会使线程进入等待队列
        // 如果只调用wait不调用pulse,可能使线程进入死锁
        // 下面执行的时间线:  t1获得锁——t1打印——2000ms——t1Pulse(此时无线程在等待队列,故无效)——2000ms——t1释放锁并进入等待队列——
        //                 t2获得锁——t2打印——2000ms——t2Pulse(此时t1线程在等待队列,t1进入就绪队列)——2000ms——t2释放锁并进入等待队列——
        //                 t1获得锁——t1Pulse(此时t2线程在等待队列,t2进入就绪队列)——t1打印——t1释放锁——t1退出——
        //                 t2获得锁——t2Pulse(此时无线程在等待队列,故无效)——t2打印——t2释放锁——t2退出
        private static void addNum()
        {
            Boolean gotLock = false;
            try
            {
                // Monitor.Enter(num); //获取排它锁
                Monitor.Enter(num, ref gotLock);
                Console.WriteLine(Thread.CurrentThread.Name+ DateTime.Now.ToString() + "——————" + num);
                //释放锁并让线程进入等待队列,直到它重新获得锁
                Thread.Sleep(2000);
                //通知等待的线程进入就绪队列,有锁了
                Monitor.Pulse(num);
                Thread.Sleep(2000);
                Monitor.Wait(num);
                Monitor.Pulse(num);
            }
            finally
            {
                Console.WriteLine(Thread.CurrentThread.Name + DateTime.Now.ToString() + "——————" + num);
                if (gotLock)
                {
                    Monitor.Exit(num);
                }
            }
        }
    }
}

运行结果:

 

用Monitor类获得对象锁的try .. catch finally的过程还有一个语法糖,lock关键字

posted @ 2015-08-20 18:29  桃子夭夭  阅读(2266)  评论(0编辑  收藏  举报