2011-05-15 86 views
1


我需要使用(目前)一些java apis --unfortunatelly-只能通過jvm屬性「配置」。
據我所知,這可能會影響多線程的,因爲它可以是一個線程修改屬性可以影響正在運行的其他情形。
所以我想在一個同步的方法中這樣做,例如關於jvm全屬性和多線程的問題

public static sychronized void someMethod(){ 
    Security.setProperty("responderURL",IP); 
    //do code here 
} 

現在看來,這是好的,但我想知道如果有就這個問題和是否有缺陷存在於這樣的情況下,任何一種設計模式嗎?

感謝

+0

像往常一樣有缺陷:過時讀取。系統屬性和任何共享變量之間沒有區別。 – bestsss 2011-05-17 11:23:05

回答

4

當你創建一個同步的靜態方法,它會同步該方法所在的類。這意味着該類中只有一個方法可以一次運行。如果這解決了你的問題,那麼完美。

然而,如果JVM中的任何其他方法修改這個類的外部或之外的對類同步的方法的那些屬性,那麼你的努力不會有任何效果。

+0

+1:靜態的好點 – Cratylus 2011-05-15 09:24:08

+0

還要注意,由於屬性是靜態的,它們可能會隨機讀取(可能是類的初始化),並且隱藏在另一個靜態字段中。這不僅僅是實際上可變的靜態,而且是任何可以從運行變爲運行的靜態。 – 2011-05-15 09:40:25

2

你不需要同步,System.setProperty已經同步方法,雖然System.getProperty不同步,屬性類擴展已經syncronized方法來訪問它的鍵值pairs.As結果哈希表,你不需要做的擔心同步問題..

編輯:

關於我的回答一些澄清;

1.如果您的方法應該工作作爲一個原子單元,它應被同步,如;

public static sychronized void someMethod(){ 
     if (System.getProperty("responderURL")==null) 
      System.setProperty("responderURL",IP); 
     //do code here 
     //some code 
     URL url = new URL(System.getProperty("responderURL"),8080,"test.txt"); 
    } 

您應該同步您的方法,因爲雖然線程1正在檢查responderURL屬性,但線程2可以設置此屬性。

2.But如果你的方法設置僅responderURL屬性,其功能並不依賴respondrURL財產電流值,你不需要同步方法..

public static void someMethod(){ 
      System.setProperty("responderURL",IP); 
      //do code here 
      //some code 
      URL url = new URL(IP,8080,"test.txt"); 
     } 
+1

@Gursel:因此,如果線程A將Security.property設置爲IP1,並且線程B嘗試將Security.property設置爲IP2,會發生什麼情況?IP2是否會覆蓋IP1? – Cratylus 2011-05-15 09:22:51

+0

它會覆蓋,但同步不會保護你。 – Kaj 2011-05-15 09:28:42

+0

@Kaj:爲什麼不呢?如果它是同步的,threadB將在threadA退出同步方法後覆蓋IP。 – Cratylus 2011-05-15 09:29:44

0

使用synchronized不會幫助你在這裏。唯一​​在你的例子做的就是確保兩個線程不能調用您的synchronized方法同時進行。

public class Foo { 
    public static synchronized void bar() { 
     //...  
    } 
} 

是完全一樣的,可以看到Foo.class並同步上它會被你的同步影響

public class Foo { 
    public static void bar() { 
     synchronized (Foo.class) { 
     //...  
     } 
    } 
} 

即唯一的代碼。由於你正在調用的任何庫中的代碼顯然不知道Foo.class,因此同步它不會產生任何影響。

如果你想保證這些系統屬性可能讀取的值都不可能運行任何代碼運行之前設置,最防彈方法是將它們傳遞作爲-D參數到啓動JVM的java命令,例如 java -DresponderURL=http://foo.bar

第二種最好的方法是,像你一樣在早期的虛擬機啓動中,在一些名爲的方法中設置屬性。如果可能的話,最好使用命令行參數來執行它,但出於以下原因:如果在您正在使用的庫中的靜態塊中讀取任何此類屬性,那麼可能會在代碼執行之前運行 ,因爲Java的字節碼驗證器可能會導致這些類在您的代碼執行任何調用它們之前進行初始化(您可以通過將-Xverify:none傳遞給Java命令來避免此問題,但如果可以這樣做,那麼您可能只需在那裏設置系統屬性無論如何)。

0

如果這是一次性配置,則在靜態初始化塊內執行此操作。如果沒有,你有什麼是經典的讀寫器問題。 javadocs有一些很好的示例解決方案。