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

  • 相关阅读:
    putty远程登录,no supported authentication methods available解决方法(腾讯云)
    spring boot 集成 springbootstarterquartz 集群版配置
    排序算法
    密码发生器
    分解质因数
    python基础面试题
    计算输入密码的时间
    论文解读(GCC)《Efficient Graph Convolution for Joint Node RepresentationLearning and Clustering》 Learner
    期望、方差、协方差 Learner
    论文解读(LGAE)《Simple and Effective Graph Autoencoders with OneHop Linear Models》 Learner
  • 原文地址:https://www.cnblogs.com/acles/p/6556479.html
Copyright © 2020-2023  润新知