2015-05-04 31 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(和版本),它可能会或可能不在堆上。 –