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時間片的浪費。所以使用的時候,也需要注意。


免責聲明!

本站轉載的文章為個人學習借鑒使用,本站對版權不負任何法律責任。如果侵犯了您的隱私權益,請聯系本站郵箱yoyou2525@163.com刪除。



 
粵ICP備18138465號   © 2018-2025 CODEPRJ.COM