Java 垃圾收集器和String.intern()
如果我这样做 垃圾收集器是否可以使用由Java 垃圾收集器和String.intern(),java,string,garbage-collection,Java,String,Garbage Collection,如果我这样做 垃圾收集器是否可以使用由StringBuilder创建的“foobar”字符串 我怀疑的是intern()方法,因为我正在用基于字符串的ID同步应用程序的一些代码块 大概是这样的: StringBuilder b = new StringBuilder(); b.append("foo").append("bar"); String s = b.toString().intern(); s = null; 这是一个桌面应用程序,有一些线程,每个登录用户在每个登录过程中都拥有一个生
StringBuilder
创建的“foobar”
字符串
我怀疑的是intern()
方法,因为我正在用基于字符串的ID同步应用程序的一些代码块
大概是这样的:
StringBuilder b = new StringBuilder();
b.append("foo").append("bar");
String s = b.toString().intern();
s = null;
这是一个桌面应用程序,有一些线程,每个登录用户在每个登录过程中都拥有一个生成的ID。我认为它可以工作:
虽然(这样您可以在JVM的生命周期内获得不同的用户id实例),但当您在该同步块内时,不会对它们进行垃圾收集(因为此时字符串仍在使用中),因此对于您的目的,它应该足够稳定
即使下次您得到另一个实例,这也只能意味着锁是无争用的,所以这并不重要
但我还是不会这么做
使用?调用
str.intern()
时,您确实可以访问string的内部实例,也就是说,如果缓存中已经存在此sting,则可以访问此实例
当你说:
String id = getUserCurrentId() // this method generates IDs with StringBuider...
synchronized(id.intern()){
// .....
}
您创建的变量包含对同一字符串的另一个引用。
所以当你说
String s = .... /* anything */
您只需将null
放入该引用。它不会影响对象本身。因此,如果GC决定删除它,它将被GC删除。您仍然可以使用源对象(即直接写入赋值运算符的对象)进行同步。当然synchronized(id.intern())
看起来还可以。虽然我不知道你为什么要这么做
顺便说一句,在程序中重新使用具有功能意义的对象进行同步是一种非常糟糕的模式。考虑以下场景。您正在使用id.intern()
进行同步。这意味着如果您的ID是例如foo
,并且程序的其他部分中有人说
s = null;
他可以访问同一个对象,因为字符串文本是缓存的。
现在,如果在程序的其他部分中写入以下代码:
String s = 'foo'
在你写的代码里
String s = 'foo';
.....
synchronized(s) {
s.notify();
}
您的
wait()
可能会退出!程序的这种意外行为很难调试。因此,更好的做法是为锁使用特殊对象 +1表示“使用特殊(和私有)对象进行锁定”,可能是团队决定的副本,不更改源代码。尽管JVM在.intern()
之后维护每个字符串的副本,但测试表明内存使用率不高。运行时生成的所有其他副本都会被正常垃圾收集。
synchronized(id.intern()) {
id.wait();
}