Java String.intern()线程安全有保证吗?

Java String.intern()线程安全有保证吗?,java,string,multithreading,Java,String,Multithreading,是否有任何文档证明String.intern()是线程安全的?javadoc提到了它,但没有直接提到它: 返回字符串对象的规范表示形式。一滩 字符串最初为空,由类字符串私下维护 调用intern方法时,如果池已包含 字符串等于由equals(对象)确定的此字符串对象 方法,则返回池中的字符串。否则,这个 字符串对象被添加到池中,并引用此字符串 对象返回 因此,对于任意两个字符串s和t,s.intern()==t.intern() 当且仅当s.equals(t)为真时为真 所有文字字符串和字符串值

是否有任何文档证明
String.intern()
是线程安全的?javadoc提到了它,但没有直接提到它:

返回字符串对象的规范表示形式。一滩 字符串最初为空,由类字符串私下维护

调用intern方法时,如果池已包含 字符串等于由equals(对象)确定的此字符串对象 方法,则返回池中的字符串。否则,这个 字符串对象被添加到池中,并引用此字符串 对象返回

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

所有文字字符串和字符串值常量表达式都是 实习。字符串文字在本手册第3.10.5节中定义 JAVA™ 语言规范

值得注意的是,javadoc表示保证返回池中的字符串,但并不是说池本身是线程安全的(因此在编写时,它似乎为在线程竞争的情况下替换池条目打开了大门,尽管我认为这种解释不太可能)

String
的JDK源代码显示
intern()
是一种本机方法,它不会对其线程安全性产生任何影响:

public native String intern();
我特别关心的是以下内容是否是完全线程安全的,以保证在面对并发请求时,每个唯一字符串值只创建一个
MyObject
(而不仅仅存储在缓存中):

public void myMethod(String myString)
{
    // Get object from cache, the cache itself is thread safe
    MyObject object = myCache.get(myString);
    if (object == null)
    {
        synchronized(myString.intern())
        {
            // Retry cache to avoid race condition
            object = myCache.get(myString);
            if (object == null)
            {
                object = new MyObject(myString);
                // ... do some startup / config of the object ...
                myCache.put(object);
            }
        }
    }
    // do something useful with the object
}
我希望避免在方法或缓存本身上进行同步,因为创建对象可能需要一些时间(需要网络访问)。有一些变通方法,比如维护本地线程安全的缓存/字符串池,但除非必要,否则不值得这么做。
String.intern()
(无法从缓存中删除插入的字符串)的内存含义与此特定用例(使用的字符串数量很少)无关

我相信
String.intern()
是线程安全的,上面的代码也很好,但是缺乏来自可靠来源的直接确认让我有点担心

这个问题以前在这里被问过多次,但没有提供具体的答案和参考:


听起来您可能想要番石榴,它以散列方式将对象映射到锁。如果您正在使用的任何其他代码都有相同的想法,那么在内部字符串上同步似乎是一种潜在的危险黑客行为。

为什么要使用
String.intern()
?为什么要在
字符串上进行同步呢?另外,如果您正在寻找线程安全、并发友好的缓存实现,请使用Guava的LoadingCache@fge为保证只构造和缓存特定字符串的一个对象。假设字符串是指向只能为其创建一个对象的资源的路径。这里的缓存只是一个同步或并发的HashMap。这听起来像是你想要一个番石榴,它以散列的方式将对象映射到锁。这可能会节省一点复杂性,但尴尬的代价似乎很高。特别是,它使您的代码与尝试在字符串上同步的任何其他代码以有趣且难以调试的方式不兼容。也许他们正在使用常量字符串“foo”作为全局锁,而您碰巧得到了一个名为“foo”的资源路径,然后您得到了。看起来你在节约复杂性,但我仍然认为这是一个脆弱的黑客行为。