MethodImplOptions.Synchronized的一点讨论

摘要:
审阅代码发现有一个具有[MethodImpl(MethodImplOptions.Synchronized)]属性的方法,并且}}实际上与以下代码相同(SyncMethodCls是包含此方法的类):您可以看到,使用[MethodImpl(MethodImplOptions.synchronization)]属性会锁定整个类型。如果这个类中只有一个静态同步方法,那么就可以了。

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

对方法加上这个属性之后,会把整个方法体加在一个同步块中,比如下面的代码:

[MethodImpl(MethodImplOptions.Synchronized)]
public static void syncDemo()
{
       if (count % 10 != 0)
       {
              Thread.Sleep(50);   
              count++;
       }       
}

其实和下面的代码是一样的(SyncMethodCls是包含这个方法的类):

public static void lockDemo()
{
       lock (typeof(SyncMethodCls))
       {
              if (count % 10 != 0)
              {
                     Thread.Sleep(50);   
                     count++;
              }   
       }
}

从第二个方法中,可以看到使用[MethodImpl(MethodImplOptions.Synchronized)]这个属性是对整个类型进行加锁的,同步块是整个方法。如果这个类中只有一个静态同步方法还好,如果有两个同步静态方法都使用这个属性进行标注,这两个方法之间就会出现竞态,在一些情况下,你可能并不想让两个不是很相关的方法出现竞态的情况。同一个类型中越多这种静态同步方法,出现的竞争越激励,系统性能也会越差。

上面也说了,使用这个属性之后,是对整个方法进行同步,但是有时候有些条件判断并不需要放在同步块中,比如上面方法中的if 条件,我并不想放到同步块中,因为有时候已经满足条件的线程就不需要再次阻塞了。这种情况在单例中最明显了,首先判断单例的实例是否为空,只有为空的时候,才会去加锁重新生成一个新的实例。

以上方法可以参考单例进行改造,改造后的代码如下:

private static object syncObj = new object();
public static void syncObjDemo()
{
    if (count % 10 !=0)
    {
        lock(syncObj)
        {
            if (count % 10 != 0)
            {
                Thread.Sleep(50);
                count++;
            }
        }
    }       
}

改造之后,竞争数量明显减少。 

下面附上使用[MethodImpl(MethodImplOptions.Synchronized)]竞争情况:

MethodImplOptions.Synchronized的一点讨论第1张

改造之后的竞争情况:

MethodImplOptions.Synchronized的一点讨论第2张

多线程调用情况如下:

for (int i = 0; i <= 1000; i++)
{
    ThreadPool.QueueUserWorkItem((t) =>
    {
        // syncMethodCls.syncDemo();
        syncMethodCls.syncObjDemo();
    });
}

到此,需要好好说说这个[MethodImpl(MethodImplOptions.Synchronized)]了,MSDN上这样解释:“该方法一次性只能在一个线程上执行。 静态方法在类型上锁定,而实例方法在实例上锁定。 只有一个线程可在任意实例函数中执行,且只有一个线程可在任意类的静态函数中执行。” 总结一句话就是:静态方法锁整个类,实例方法锁整个实例。这句话乍一看挺吓人的,但是如果你的类中只有一个同步方法的话,锁整个类和整个实例影响也不大,但是要确保类和实例在其他地方不会再次被锁,否则会造成死锁的。

所以这个属性,还是尽量不要使用了,不光有可能造成性能问题不说,还有可能造成死锁的严重问题。

说到锁整个类,最近看java多线程的部分,java中有个和C#的lock类似的同步关键字synchronized,好多例子都是直接在方法上加这个关键字,实现方法的同步实现。这个关键字实现的方式应该类似MethodImplOptions.Synchronized,静态方法锁类型,实例方法锁实例,而且如果有条件判断可能还会造成不必要的阻塞。而且由于jdk对synchronized的不断优化,在有些时候并不会马上进行加锁,而是会先自旋一会(以通过浪费CPU时间减少阻塞),可能在某些时候造成CPU时间片的浪费。所以使用的时候,也需要注意。

免责声明:文章转载自《MethodImplOptions.Synchronized的一点讨论》仅用于学习参考。如对内容有疑问,请及时联系本站处理。

上篇sql server中的工作线程mysql实战笔记下篇

宿迁高防,2C2G15M,22元/月;香港BGP,2C5G5M,25元/月 雨云优惠码:MjYwNzM=

相关文章

redis哨兵

Redis sentinel(哨兵)模块已经被集成在redis2.4+的版本中,尽管目前不是release,不过可以尝试去使用和了解,事实上sentinel还是有点复杂的. sentinel主要功能就是为Redis M-S(master,slaves)集群提供了1)master存活检测 2)集群中M-S服务监控 3) 自动故障转移,M-S角色转换等能力,...

HTML5--Range对象的基本操作(5)

前言:   这节课主要学习HTML5中关于Range对象的常用API。   1.Range对象初识     作用:一个Range对象代表页面上的一段连续区域。通过Range对象,可以获取或修改网页上的任何区域。     Rnage对象示例: <body> Range对象初识</br> <input id="bt...

Java IO系列之一:IO

1. 概述  Java IO一般包含两个部分:   1.java.io包中堵塞型IO;   2.java.nio包中的非堵塞型IO,通常称为New IO。 java.io包下,分为四大块近80个类: 1、基于字节操作的I/O接口:InputStream和OutputStream 2、基于字符操作的I/O接口:Writer和Reader 3、基于磁盘操作的I...

embed 元素的用法

embed (一)、基本语法: embed src=url 说明:embed可以用来插入各种多媒体,格式可以是 Midi、Wav、AIFF、AU、MP3等等,Netscape及新版的IE 都支持。url为音频或视频文件及其路径,可以是相对路径或绝对路径。 示例:<embed src="http://t.zoukankan.com/your.mid"&...

[转]SIFT,SURF,ORB,FAST 特征提取算法比较

转载地址:https://blog.csdn.net/vonzhoufz/article/details/46461849 主要的特征检测方法有以下几种,在一般的图像处理库中(如opencv, VLFeat, Boofcv等)都会实现。 FAST ,Machine Learning for High-speed Corner Detection, 200...

用UIButton实现页面跳转(AppDelegate +NavigationViewController)

1.AppDelegate.h 定义一个UINavigationController  #import <UIKit/UIKit.h> #import "MainViewController.h"   @interface AppDelegate : UIResponder <UIApplicationDelegate>   @pr...