[MethodImpl(MethodImplOptions.Synchronized)]与lock机制

在进行.NET开发时,经常会遇见如何保持线程同步的情况。在众多的线程同步的可选方式中,加锁无疑是最为常用的。如果仅仅是基于方法级别的线程同步,使用System.Runtime.CompilerServices.MethodImplAttribute无疑是最为简洁的一种方式。MethodImplAttribute可以用于instance method,也可以用于static method。当在某个方法上标注了MethodImplAttribute,并指定MethodImplOptions.Synchronized参数,可以确保在不同线程中运行的该方式以同步的方式运行。

查阅MSDN的说明:

The method can be executed by only one thread at a time. Static methods lock on the type, whereas instance methods lock on the instance. Only one thread can execute in any of the instance functions, and only one thread can execute in any of a class's static functions.
 
这个方法一次只能执行一个线程。静态方法锁定类型,而实例方法锁定实例。只有一个线程可以在任何一个实例函数中执行,而且只有一个线程可以在任何一个类的静态函数中执行。

可以看出:

  • [MethodImplAttribute(MethodImplOptions.Synchronized)]仍然是采用加锁的机制实现线程的同步。
  • 如果它被应用到instance method,相当于对当前实例加锁。
  • 如果它被应用到static method,相当于当前类型加锁

可参考文章:

[MethodImpl(MethodImplOptions.Synchronized)]、lock(this)与lock(typeof(...))

  • lock机制

关键字lock的作用是锁定某一代码块,让同一时间只有一个线程访问该代码块。

lock(X)
{
  //需要锁定的代码....
}

那么为什么上面这段话能够锁定代码?其中的奥妙就是X这个对象,事实上X是任意一种引用类型,它在这儿起的作用就是任何线程执行到lock(X)时候,X需要独享才能运行下面的代码,若假定现在有3个线程A,B,C都执行到了lock(X)而ABC因为此时都占有X,这时ABC就要停下来排个队,一个一个使用X,从而起到在下面的代码块内只有一个线程在运行(因为此时只有一个线程独享X,其余两个在排队),所以这个X必须是所有要执行临界区域代码进程必须共有的一个资源,从而起到抑制线程的作用。

lock最需要注意的一个问题就是线程死锁,MSDN上列出了3个典型问题:

通常,应避免锁定 public 类型,否则实例将超出代码的控制范围。常见的结构 lock (this)、lock (typeof (MyType)) 和 lock ("myLock") 违反此准则:

  1. 如果实例可以被公共访问,将出现 lock (this) 问题。
  2. 如果 MyType 可以被公共访问,将出现 lock (typeof (MyType)) 问题。
  3. 由于进程中使用同一字符串的任何其他代码将共享同一个锁,所以出现 lock(“myLock”) 问题。

最佳做法是定义 private 对象来锁定, 或 private shared 对象变量来保护所有实例所共有的数据。

  • lock的内涵(Monitor类)

另外,使用lock来实现C#线程同步,在C#编译器编译lock语句时,将其编译成了调用Monitor类。一条lock语句会被编译成调用Monitor的Enter和Exit方法。Monitor在 System.Threading命名空中。lock的功能就相当于直接调用Monitor的Entry方法,所不同的是,lock方法在结束后,会自动解除锁定,当然,在IL中是调用了Monitor的Exit方法,但在C#程序中,看起来是自动解锁的,这类似于C#中的using语句,可以自动释放数据库等资源。但如果直接在C#源程序中使用Monitor类,就必须调用Exit方法来显式地解除锁定。

示例:

Monitor.Enter(lockObj); 
try
    // 代码
catch(Exception e) 
    // 异常处理代码 
finally
    Monitor.Exit(lockObj);  // 解除锁定 

Exit方法最后在finally里调用,这样无论在方法在发生异常、返回还是正常执行,都会执行到finally,并调用Exit方法解除锁定。

Monitor类不仅可以完全取代lock语句,还可以使用TryEntry方法设置一个锁定超时。

示例:

if(Monitor.TryEntry(lockObj, 1000)) 
    try
    
    
    finally
    
        Monitor.Exit(lockObj); 
    
else
    // 超时后的处理代码 

设置锁定超时时间为1秒,即在1秒中后,lockObj还未被解锁,TryEntry方法就会返回false,如果在1秒之内,lockObj被解锁,TryEntry返回true。这种方法对于避免死锁提供了一种不错的思路。

[MethodImpl(MethodImplOptions.Synchronized)]与lock机制的更多相关文章

  1. C# Note26: [MethodImpl(MethodImplOptions.Synchronized)]与lock机制

    在进行.NET开发时,经常会遇见如何保持线程同步的情况.在众多的线程同步的可选方式中,加锁无疑是最为常用的.如果仅仅是基于方法级别的线程同步,使用System.Runtime.CompilerServ ...

  2. [MethodImpl(MethodImplOptions.Synchronized)]、lock(this)与lock(typeof(...))

    对于稍微有点经验的.NET开发人员来说,倘若被问及如何保持线程同步,我想很多人都能说好好几种.在众多的线程同步的可选方式中,加锁无疑是最为常用的.如果仅仅是基于方法级别的线程同步,使用System.R ...

  3. [MethodImpl(MethodImplOptions.Synchronized)]

    在NopCommerce项目的Nop.Core类库中有一个EngineContext类中有一个Initialize方法用到了[MethodImpl(MethodImplOptions.Synchron ...

  4. C#方法同步 [MethodImpl(MethodImplOptions.Synchronized)]

    using System; using System.Collections.Generic; using System.Linq; using System.Text; using System.T ...

  5. MethodImplOptions.Synchronized的一点讨论

    Review代码发现有一个方法加了[MethodImpl(MethodImplOptions.Synchronized)] 属性,这个属性的目的,从名字上就可以看出,是要对所有线程进行同步执行. 对方 ...

  6. Synchronized和lock的区别和用法

    一.synchronized和lock的用法区别 (1)synchronized(隐式锁):在需要同步的对象中加入此控制,synchronized可以加在方法上,也可以加在特定代码块中,括号中表示需要 ...

  7. synchronized 与 lock 的区别

    synchronized 和 lock 的用法区别 synchronized(隐式锁):在需要同步的对象中加入此控制,synchronized 可以加在方法上,也可以加在特定代码块中,括号中表示需要锁 ...

  8. 转:synchronized和LOCK的实现原理---深入JVM锁机制

    JVM底层又是如何实现synchronized的? 目前在Java中存在两种锁机制:synchronized和Lock,Lock接口及其实现类是JDK5增加的内容,其作者是大名鼎鼎的并发专家Doug ...

  9. java 锁机制(synchronized 与 Lock)

    在java中,解决同步问题,很多时候都会使用到synchronized和Lock,这两者都是在多线程并发时候常使用的锁机制. synchronized是java中的一个关键字,也就是说是java内置的 ...

随机推荐

  1. gin框架中项目的初始化

    核心知识点 json配置文件解析成结构体 将路由对应的接口抽离到单独的文件中,main函数中直接注册路由即可 项目目录图 项目代码 app.json代码 { "app_name": ...

  2. Ldap主从复制搭建

    LDAP是轻量目录访问协议(Lightweight Directory Access Protocol)的缩写, LDAP协议的特点 读取速度远高于写入速度. 对查询做了优化,读取速度优于普通关系数据 ...

  3. JavaScript设计原则与编程技巧

    1 设计原则概述 <UNIX/LINUX设计哲学>设计准则 ① 小既是美. ② 每个程序只做一件事情. ③ 快速建立原型. ④ 舍弃高效率而取可移植性. ⑤ 避免强制性的图形化界面交互. ...

  4. Java多线程专题3: Thread和ThreadLocal

    合集目录 Java多线程专题3: Thread和ThreadLocal 进程, 线程, 协程的区别 进程 Process 进程提供了执行一个程序所需要的所有资源, 一个进程的资源包括虚拟的地址空间, ...

  5. 解决mybatis拦截器无法注入spring bean的问题

    公司要整合rabbitmq与mybatis拦截器做一个数据同步功能. 整合过程中大部分环节都没什么问题,就是遇到了mybatis拦截器 @Intercepts(@Signature(type = Ex ...

  6. 谷歌CEO桑达尔·皮查伊:区块链可能撼动云计算

    谷歌CEO桑达尔·皮查伊在周二的季度收益电话会议上承认了Web3和区块链的力量. 皮查伊表示,Web3描述了基于区块链的互联网新愿景,区块链是一种分散.安全.透明的技术,支持加密货币网络.不可替代代币 ...

  7. SnapKit

    SnapKit 是 Masonry 框架的团队针对 Swift 全新开发的一套自动布局框架 官方网站:http://snapkit.io github网站:https://github.com/Sna ...

  8. java实现多线程生产者消费者模式

    1.概念 生产者消费者模式就是通过一个容器来解决生产者和消费者的强耦合问题.生产者和消费者彼此之间不直接通讯,而通过阻塞队列来进行通讯,所以生产者生产完数据之后不用等待消费者处理,直接扔给阻塞队列,消 ...

  9. Google hacker

    转载请注明来源:https://www.cnblogs.com/hookjc/ Google Hacking其实并算不上什么新东西,在早几年我在一些国外站点上就看见过相关的介绍,但是由于当时并没有重视 ...

  10. ◆JAVA加密解密-DES

    DES算法提供CBC, OFB, CFB, ECB四种模式,MAC是基于ECB实现的. 一.数据补位 DES数据加解密就是将数据按照8个字节一段进行DES加密或解密得到一段8个字节的密文或者明文,最后 ...