2011-08-01 59 views
4

在下面的例子併發執行靜態和非靜態同步方法的問題?

  1. 如果不同的線程試圖同時訪問靜態和 非靜態同步方法,進而嘗試 改變使用兩種方法中的靜態數據會發生什麼?
  2. 使用run()方法的do-while循環到 是否有任何問題爲每個非靜態的 同步方法調用創建類BadDesign的新對象?
  3. 此Java代碼是否正確同步?

下面是示例代碼說明我的問題:

BadDesign.java

public final class BadDesign{ 

    private static int sensitiveData; 

    public synchronized static void changeDataViaStaticMethod(int a){ 
     //... updating the sensitiveData 
     sensitiveData = a; 
    } 


    public synchronized void changeDataViaNonStaticMethod(int b){ 
     //... updating the sensitiveData 
     sensitiveData = b; 
    } 


    public static void showSensitiveDataStatic(){ 
     System.out.println("Static: " + Thread.currentThread().getName()+ " - " + sensitiveData); 
    } 


    public void showSensitiveData(){ 
     System.out.println(Thread.currentThread().getName() + " - " + sensitiveData); 
    } 


    public static void main(String[] args){ 

     new Thread(new TestThread11()).start(); 
     new Thread(new TestThread11()).start(); 
    } 
} 

而且TestThread11.java

class TestThread11 implements Runnable{ 
    public void run(){ 
     int i = 0; 

     do{ 
      BadDesign.changeDataViaStaticMethod(5); 
      BadDesign.showSensitiveDataStatic(); 

      //... new object for every iteration 

      //... so synchronization of non-static method 

      //... doesn't really do anything significant here 

      BadDesign bd = new BadDesign(); 
      bd.changeDataViaNonStaticMethod(10); 
      bd.showSensitiveData(); 

     }while (i++ < 100); 
    } 
} 
+0

我很累,很早在早上編輯一篇文章。我會讓其他敏銳的編輯出現並佔據這個堡壘。 ;-) –

+0

@The精英紳士 - 你們不睡覺:P。考慮編輯它。 – Perception

回答

2
  1. 由多個線程存取的靜態和非靜態數據是由不同的電平的鎖處理。該訪問非靜態方法的線程共享的對象級鎖(也就是每對象),其中作爲訪問靜態方法,你需要一流水平鎖(這是1元類)
  2. 沒有與DO-而沒有問題環路,如

    BadDesign.changeDataViaStaticMethod(5); //needs BadDesign Class lock.  
        BadDesign.showSensitiveDataStatic(); //does not need any lock 
    

 bd.changeDataViaNonStaticMethod(10); // needs lock for bd object. 
     bd.showSensitiveData();    //does not need any lock 

我希望回答你的問題。

+1

好..謝謝你..所以上面的代碼是否合適synchoronised或沒有好的 – chinchu

+0

ahh..ok。您在showSensitiveData()中編寫的代碼永遠不會線程安全。這意味着多個線程可以同時訪問這個方法,因爲它不同步。所以如果你寫了類似的東西,遞增一些全局值,並期望它在每個線程中顯示正確的值,那麼可能會忽略該情況。 – Swagatika

6

非靜態版本將允許兩個不同的線程通過不同的對象進入,獲取不同的鎖並仍然訪問相同的共享數據。從根本上說,這不是線程安全的,基本上使鎖無用。你想要任何一條共享數據被所覆蓋,一個鎖。

你仍然可以使用非靜態方法,如果你真的想(例如,如果結果應該通過實例數據以及部分確定),但你應該通過一個共享鎖,例如訪問共享數據

private static final Object staticLock = new Object(); 

... 

synchronized (staticLock) 
{ 
    // Read or write static data 
} 
+0

@chinchu:你什麼意思?我已經表明你必須使用同步語句。你的意思是使用同步*方法*?如果是這樣,我會親自避免那些開始 - 避免暴露你的鎖,除非你真的必須。 –

+1

Yah先生....你是正確的.. :-)我的意思是使用同步的method.okay! – chinchu

+0

@chichu:正確 - 同步方法基本上等價於在其中有'synchronized(this)'或'synchronized(TheDeclaringClass.class)'語句。不是一個好主意,因爲鎖定在同一監視器上的任何其他人都可能導致死鎖。 –

1

我假設這是某種課程。看來這個特殊問題的關鍵是要突出兩個基本的基礎知識的Java

  1. 任何對象都可以作爲顯示器中的Java
  2. 如何​​隱式使用當前對象實例的鎖

第一點是關於理解監視器是什麼。我邀請您學習Java語言規範的相關部分,Threads and Locks。顯示器是一個線程可以解鎖。當一個線程鎖定它時,任何試圖鎖定該特定監視器的其他線程都會等待(阻止),直到第一個線程解鎖它。

第2點是關於Java中的編譯器功能。當您指定某些內容爲​​而未明確指示要使用哪個監視器時,Java將使用被調用對象的實例。但是,如果方法是靜態的,它將使用java.lang.Class)的實例作爲監視器。這在現實中意味着什麼?由於類加載器上下文中每個類對象只有一個唯一的全局實例,因此靜態方法只有一個監視器。相比之下,實例方法將使用被稱爲監視器的對象實例,以便每個對象都擁有自己的監視器。 靜態方法全局同步,實例方法爲類的每個特定實例同步。