锁、C#中Monitor和Lock以及区别

简介: 1.Monitor.Enter(object)方法是获取锁,Monitor.Exit(object)方法是释放锁,这就是Monitor最常用的两个方法,当然在使用过程中为了避免获取锁之后因为异常,致锁无法释放,所以需要在try{} catch(){}之后的finally{}结构体中释放锁(Monitor.Exit())。

1.Monitor.Enter(object)方法是获取锁,Monitor.Exit(object)方法是释放锁,这就是Monitor最常用的两个方法,当然在使用过程中为了避免获取锁之后因为异常,致锁无法释放,所以需要在try{} catch(){}之后的finally{}结构体中释放锁(Monitor.Exit())。

  2.Monitor的常用属性和方法:

    Enter(Object) 在指定对象上获取排他锁。

    Exit(Object) 释放指定对象上的排他锁。

    IsEntered 确定当前线程是否保留指定对象锁。

    Pulse 通知等待队列中的线程锁定对象状态的更改。

    PulseAll 通知所有的等待线程对象状态的更改。

    TryEnter(Object) 试图获取指定对象的排他锁。

    TryEnter(Object, Boolean) 尝试获取指定对象上的排他锁,并自动设置一个值,指示是否得到了该锁。

    Wait(Object) 释放对象上的锁并阻止当前线程,直到它重新获取该锁。

                                       Lock关键字

  1.Lock关键字实际上是一个语法糖,它将Monitor对象进行封装,给object加上一个互斥锁,A进程进入此代码段时,会给object对象加上互斥锁,此时其他B进程进入此代码段时检查object对象是否有锁?如果有锁则继续等待A进程运行完该代码段并且解锁object对象之后,B进程才能够获取object对象为其加上锁,访问代码段。

  2.Lock关键字封装的Monitor对象结构如下:

try
            {
                Monitor.Enter(obj);
                dosomething();
            }
            catch(Exception ex)
            {
                
            }
            finally
            {
                Monitor.Exit(obj);
            }

 3.锁定的对象应该声明为private static object obj = new object();尽量别用公共变量和字符串、this、值类型。

Monitor和Lock的区别

  1.Lock是Monitor的语法糖。

  2.Lock只能针对引用类型加锁。

  3.(使用 Monitor 锁定对象(即引用类型)而不是值类型。)。

  4.Monitor还有其他的一些功能。

class Program
    {
        private static object obj = new object();
        public void LockSomething()
        {
            lock (obj)
            {
                dosomething();
            }
        }
        public void MonitorSomeThing()
        {
            try
            {
                Monitor.Enter(obj);
                dosomething();
            }
            catch(Exception ex)
            {
                
            }
            finally
            {
                Monitor.Exit(obj);
            }
        }

        public void dosomething()
        { 
            //做具体的事情
        }
    }

Monitor 类通过向单个线程授予对象锁来控制对对象的访问。对象锁提供限制访问代码块(通常称为临界区)的能力。当一个线程拥有对象的锁时,其他任何线程都不能获取该锁。还可以使用 Monitor 来确保不会允许其他任何线程访问正在由锁的所有者执行的应用程序代码节,除非另一个线程正在使用其他的锁定对象执行该代码。

Monitor 具有以下功能:

  • 它根据需要与某个对象相关联。

  • 它是未绑定的,也就是说可以直接从任何上下文调用它。

  • 不能创建 Monitor 类的实例。

将为每个同步对象来维护以下信息:

  • 对当前持有锁的线程的引用。

  • 对就绪队列的引用,它包含准备获取锁的线程。

  • 对等待队列的引用,它包含正在等待锁定对象状态变化通知的线程。

  • 下表描述了访问同步对象的线程可以采取的操作:

     

    操作

    说明

    EnterTryEnter

    获取对象锁。此操作同样会标记临界区的开头。其他任何线程都不能进入临界区,除非它使用其他锁定对象执行临界区中的指令。

    Wait

    释放对象上的锁以便允许其他线程锁定和访问该对象。在其他线程访问对象时,调用线程将等待。脉冲信号用于通知等待线程有关对象状态的更改。

    Pulse (信号), PulseAll

    向一个或多个等待线程发送信号。该信号通知等待线程锁定对象的状态已更改,并且锁的所有者准备释放该锁。等待线程被放置在对象的就绪队列中以便它可以最后接收对象锁。一旦线程拥有了锁,它就可以检查对象的新状态以查看是否达到所需状态。

    Exit

    释放对象上的锁。此操作还标记受锁定对象保护的临界区的结尾。

    使用 Enter 和 Exit 方法标记临界区的开头和结尾。如果临界区是一个连续指令集,则由 Enter 方法获取的锁将保证只有一个线程可以使用锁定对象执行所包含的代码。在这种情况下,建议您将这些指令放在 try 块中,并将 Exit 指令放在 finally 块中。此功能通常用于同步对类的静态或实例方法的访问。如果实例方法需要同步线程访问,则它将使用当前实例作为要锁定的对象调用 Enter 和对应的 Exit 方法。由于只能有一个线程持有当前实例上的锁,因此该方法一次只能由一个线程来执行。静态方法是使用当前实例的 Type 作为锁定对象以类似的方式来保护的。Enter 和 Exit 方法提供的功能与 C# lock 语句(在 Visual Basic 中为 SyncLock)提供的功能相同,区别在于 lock 和 SyncLock 以 tryfinally 块(在 Visual Basic 中为 TryFinally)来包装 Exit 方法,以确保释放监视器。

    如果临界区跨越整个方法,则可以通过将 System.Runtime.CompilerServices.MethodImplAttribute 放置在方法上并在 MethodImplAttribute 的构造函数中指定 Synchronized 值来实现上述锁定功能。使用该属性后就不需要 Enter 和 Exit 语句了。请注意,该属性将使当前线程持有锁,直到方法返回;如果可以更早释放锁,则使用 Monitor 类或 C#lock 语句而不是该属性。

    尽管锁定和释放给定对象的 Enter 和 Exit 语句可以跨越成员或类的边界或同时跨越两者的边界,但并不推荐这样做。

    当选择要同步的对象时,应只锁定私有或内部对象。锁定外部对象可能导致死锁,这是因为不相关的代码可能会出于不同的目的而选择锁定相同的对象。

  • 以上来自MSDN、
  • @陈卧龙的博客
相关文章
|
6月前
|
C#
C#学习相关系列之yield和return的区别
C#学习相关系列之yield和return的区别
|
6月前
|
安全 编译器 C#
C#学习相关系列之多线程---lock线程锁的用法
C#学习相关系列之多线程---lock线程锁的用法
|
6月前
|
C#
C#中IsNullOrEmpty和IsNullOrWhiteSpace的区别?
C#中IsNullOrEmpty和IsNullOrWhiteSpace的区别?
|
6月前
|
C#
C#系列之ref和out的区别
C#系列之ref和out的区别
199 0
|
10天前
|
Java 物联网 编译器
C#一分钟浅谈:.NET Core 与 .NET 5 区别
本文对比了 .NET Core 和 .NET 5,从历史背景、主要区别、常见问题及易错点等方面进行了详细分析。.NET Core 侧重跨平台支持和高性能,而 .NET 5 在此基础上统一了 .NET 生态系统,增加了更多新特性和优化。开发者可根据具体需求选择合适的版本。
32 7
|
13天前
|
开发框架 安全 .NET
C#面:Server.UrlEncode、HttpUtility.UrlDecode的区别
通过上述详细的解释和实例分析,相信大家对 `Server.UrlEncode` 和 `HttpUtility.UrlDecode` 的区别有了更深刻的理解,并能在实际开发中灵活运用。
23 0
|
1月前
|
网络协议 网络性能优化 C#
C# 一分钟浅谈:UDP 与 TCP 协议区别
【10月更文挑战第8天】在网络编程中,传输层协议的选择对应用程序的性能和可靠性至关重要。本文介绍了 TCP 和 UDP 两种常用协议的基础概念、区别及应用场景,并通过 C# 代码示例详细说明了如何处理常见的问题和易错点。TCP 适用于需要可靠传输和顺序保证的场景,而 UDP 适用于对延迟敏感且可以容忍一定数据丢失的实时应用。
32 1
|
5月前
|
存储 安全 Java
程序与技术分享:C#值类型和引用类型的区别
程序与技术分享:C#值类型和引用类型的区别
44 0
|
1月前
|
C# 开发者
【捞底干货】C#中equals和==运算符的区别
【捞底干货】C#中equals和==运算符的区别
28 1
|
2月前
|
C# 索引
C# 一分钟浅谈:接口与抽象类的区别及使用
【9月更文挑战第2天】本文详细对比了面向对象编程中接口与抽象类的概念及区别。接口定义了行为规范,强制实现类提供具体实现;抽象类则既能定义抽象方法也能提供具体实现。文章通过具体示例介绍了如何使用接口和抽象类,并探讨了其实现方式、继承限制及实例化差异。最后总结了选择接口或抽象类应基于具体设计需求。掌握这两者有助于编写高质量的面向对象程序。
117 5