是否有记载保证
返回字符串对象的规范表示。类String私有地维护着一个最初为空的字符串池。
当调用intern方法时,如果该池已经包含一个等于此String对象的字符串(根据equals(Object)方法确定),则返回池中的字符串。否则,将该String对象添加到池中,并返回对该String对象的引用。
由此可以得出结论:对于任何两个字符串s和t,当且仅当s.equals(t)为true时,s.intern() == t.intern()才为true。
所有文字字符串和值为字符串的常量表达式都被驻留。字符串文字在The Java™ Language Specification第3.10.5节中定义。
值得注意的是,Javadoc表示保证返回池中的字符串,但并未说明池本身是线程安全的(所以写作方式似乎为竞争线程可能会替换池条目敞开了大门,尽管我认为这种解释不太可能)。
JDK源码显示
我希望避免在方法或缓存本身上同步,因为对象的创建可能需要一些时间(需要网络访问)。有一些解决方法,例如维护一个本地线程安全的字符串缓存/池,但除非必要,否则不值得这样做。在这种特定用例中,
我相信
这个问题之前已经在这里多次提出过,但没有提供具体的答案和参考资料:
String.intern()
是线程安全的?Java文档暗示了这一点,但并没有直接解释:返回字符串对象的规范表示。类String私有地维护着一个最初为空的字符串池。
当调用intern方法时,如果该池已经包含一个等于此String对象的字符串(根据equals(Object)方法确定),则返回池中的字符串。否则,将该String对象添加到池中,并返回对该String对象的引用。
由此可以得出结论:对于任何两个字符串s和t,当且仅当s.equals(t)为true时,s.intern() == t.intern()才为true。
所有文字字符串和值为字符串的常量表达式都被驻留。字符串文字在The Java™ Language Specification第3.10.5节中定义。
值得注意的是,Javadoc表示保证返回池中的字符串,但并未说明池本身是线程安全的(所以写作方式似乎为竞争线程可能会替换池条目敞开了大门,尽管我认为这种解释不太可能)。
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()
的内存影响(无法从缓存中删除 interned 字符串)与此无关(仅使用少量字符串)。我相信
String.intern()
是线程安全的,上面的代码也没问题,但是缺乏来自可靠来源的直接确认让我稍感担忧。这个问题之前已经在这里多次提出过,但没有提供具体的答案和参考资料:
String.intern()
?为什么要在意同步String
呢? - fgeStriped<Lock>
,它以哈希方式将对象映射到锁。 - Louis Wasserman