zoukankan      html  css  js  c++  java
  • 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关键字

  • 相关阅读:
    Nhibernate 3.0 cookbook学习笔记 配置与架构
    jQuery 三级联动选项栏
    依赖注入框架Autofac学习笔记
    Windows服务初探
    再记面试题
    Nhibernate 3.0 cookbook学习笔记 一对多与多对多映射
    Nhibernate 3.0 cookbook学习笔记 创建一个加密类
    2011 微软 MVP 全球大会即将拉开序幕
    Windows Shell扩展系列文章 2 .NET 4为扩展的Windows Shell上下文菜单项添加位图图标
    【转】微软一站式示例代码库(中文版)20110413版本, 新添加16个Sample
  • 原文地址:https://www.cnblogs.com/tzyy/p/4746023.html
Copyright © 2011-2022 走看看