zoukankan      html  css  js  c++  java
  • MethodImplOptions.Synchronized的一点讨论

    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)]竞争情况:

    改造之后的竞争情况:

    多线程调用情况如下:

    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时间片的浪费。所以使用的时候,也需要注意。

  • 相关阅读:
    常用工具
    H5页面验收流程及性能验收标准
    埋点数据测试
    提高效率的必备工具
    移动APP安全测试
    Response响应相关
    AES加密解密
    Requests模块
    爬虫入门
    【CMDB】API传输验证
  • 原文地址:https://www.cnblogs.com/acles/p/6556479.html
Copyright © 2011-2022 走看看