2013-02-10 97 views
12

我想在Java中使用String.intern()来节省内存(使用具有相同内容的字符串的内部池)。我从不同的线程调用这个方法。这是个问题吗?是String.intern()线程安全

+4

如果不是线程安全,会感到非常惊讶。那是图书馆设计中的一个主要缺陷。 – CodesInChaos 2013-02-10 13:05:36

+0

这些字符串从哪里来? – jlordo 2013-02-10 13:06:27

+0

@jlordo - 任何不是编译时常量的字符串表达式都不会自动实现。因此,例如,'new String(“abc”)!=“abc”';但是,'“ab”+“c”==“abc”'(因为实习)。 – 2013-02-10 13:11:13

回答

4

你的问题的简短答案是肯定的。它是线程安全的。

但是,您可能想重新考虑使用此功能来减少内存消耗。原因是你无法从实习字符串列表中删除任何实体。更好的解决方案是为此创建自己的设施。所有你需要的是你的字符串存储在一个HashMap<String,String>像这样:

public String getInternedString(String s) { 
    synchronized(strings) { 
     String found = strings.get(s); 
     if(found == null) { 
      strings.put(s, s); 
      found = s; 
     } 
     return found; 
    } 
} 
+3

(加上锁定,因为OP希望线程安全) – CodesInChaos 2013-02-10 13:15:46

+2

你还可以提到可怕的'实习生'表现。如果我没有记错,时间复杂度为O(* n *),其中* n *是字符串池的当前大小。 – 2013-02-10 13:17:49

+0

不应该是'if(found == null)'?而且,正如所写的,即使'strings'是一个线程安全的数据结构,这也不是线程安全的。 – 2013-02-10 19:37:58

1
  • 由于返回一个不可变的Java字符串,该方法是线程安全的。您无法按原样操作字符串。

  • 该文档确实暗示它线程安全。 (通过强调任何

由此可见任何两个字符串s和t,s.intern()== t.intern() 为真,当且仅当S .equals(t)是真的。

  • 第三,JNI的接口使用的C语言jobject秒。 jstring就是其中之一,并且与定义一样,所有jobject都是不可变的。因此,同样在本地c级别上,我们保留了线程安全性。

命名这些,我们有充足的理由说它是线程安全的。

PS:但是,如果您使用多个类加载器,则最终可能会产生具有挑战性的结果,因为字符串池按照String-class来维护。

A pool of strings, initially empty, is maintained privately by the class String. 
+0

'java.lang.String'只能由引导类加载器加载。 – irreputable 2013-02-10 20:59:13

+0

@irreputable我不知道你会怎么做,但如果有人这样做可能很重要。 – poitroae 2013-02-11 10:14:32