2015-05-04 28 views
4

上同步我寫一些這樣的代碼:的Java:String對象

public static void function7() { 
    String str = "123"; 
    String str2 = "123"; 
    synchronized (str) { 
     if(str != null) { 
      str2 = "123"; 
     }else{ 
      str = "456"; 
     } 
     System.out.println(str2); 
    } 
} 

的代碼編譯好。 但是Eclipse的插件,發現漏洞,給後續的錯誤報告:

常量字符串拘禁和跨由JVM加載的所有其他類共享。因此,這可能會鎖定其他代碼也可能鎖定的內容。這可能會導致非常奇怪和難以診斷阻塞和死鎖行爲。

究竟是什麼意思?

+0

另請參見[在Java中同步字符串對象](https://stackoverflow.com/questions/133988/synchronizing-on-string-objects-in-java)。 – Vadzim

回答

3

字符串文字是不可變的,並通過虛擬機的字符串池共享。這意味着每次寫入時,例如"foo",代表foo的新字符串都不會放在堆上。因此,此字符串池對所有線程均可見。在字符串文字上同步,然後暴露給非結構化同步,這是死鎖地獄列車上的第一站。

字符串的高效共享是爲什麼你不應該使用帶有簽名String(String)的String構造函數,除非你真的有這麼做的理由。

此外,在本地變量上同步沒有意義,因爲在方法之外沒有可見性,更不用說在其他線程中。

最後,你真的需要同步嗎?既然你沒有在上面的代碼中有效地使用它,即使排除了字符串問題,也可能不需要使用它。

+1

好吧,我不認爲我已經使用String構造函數的簽名String(String)..... 看起來重點是*不應該*同步一個可能被重用的對象,因爲這也被指向FindBugs的。 –

+0

@Steve,'表示foo的字符串沒有放在堆上。「你確定嗎?我不這麼認爲。 'foo'也在堆中,但在String池中。 – UnKnown

+0

JVM規範中未指定字符串池的位置;取決於您使用的JVM(和版本),它可能會或可能不在堆上。 –