String.intern() 线程安全吗?

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

4
如果这个库不是线程安全的话,那会让人非常惊讶。这将是该库设计中的一个重大缺陷。 - CodesInChaos
这些字符串来自哪里? - jlordo
@jlordo - 任何不是编译时常量的字符串表达式都不会自动合并。例如,new String("abc") != "abc";但是,"ab" + "c" == "abc"(因为合并)。 - Ted Hopp
这是一个本地方法,所以你必须查看源代码才能确定,但如果不是的话,我会非常惊讶。 - Perception
@TedHopp:我知道这一点。不过,我们仍然不知道OP代码中的字符串来自何处。 - jlordo
@jlordo - 为什么这很重要? - Ted Hopp
2个回答

5

回答你的问题,是的,它是线程安全的。

然而,你可能需要重新考虑使用这个功能来减少内存消耗。原因是你无法从字符串池中删除任何条目。更好的解决方案是创建自己的功能。你只需要将字符串存储在像这样的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;
    }
}

2
你也可以提到可怕的 intern 性能。如果我没记错的话,时间复杂度是 O(n),其中 n 是字符串池当前的大小。 - Marko Topolnik
这不应该是 if (found == null) 吗?而且,即使 strings 是线程安全的数据结构,按照现在的写法,它也几乎不是线程安全的。 - Ted Hopp
使用ConcurrentHashMap更简单,不用担心自己加锁的问题。 - Bohemian
我最初在那里没有任何synchronized块,因为有多种表达方式。显然那是错误的选择,我已经编辑它以包括它。 - Elias Mårtenson
@Bohemian:或者使用Guava的Interner(http://docs.guava-libraries.googlecode.com/git/javadoc/com/google/common/collect/Interners.html)。 - Daniel Pryden
显示剩余3条评论

3
  • 返回一个不可变的Java-String,该方法是线程安全的。您不能直接操作该字符串。

  • 文档确实表明它是线程安全的(通过强调任何)。

因此,对于任何两个字符串s和t,当且仅当s.equals(t)为真时,s.intern() == t.intern()才为真。

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

总之,我们有充分的理由说它是线程安全的。

PS:但是,如果您使用多个类加载器,则可能会遇到挑战性的结果,因为String池是按String类维护的。

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

1
java.lang.String 只能由引导类加载器加载。 - irreputable
@irreputable 我不确定你会如何做,但如果有人这样做可能会有所影响。 - poitroae

网页内容由stack overflow 提供, 点击上面的
可以查看英文原文,
原文链接