简体   繁体   English

垃圾收集器和String.intern()

[英]Garbage collector and String.intern()

If I do 如果我做

StringBuilder b = new StringBuilder();
b.append("foo").append("bar");
String s = b.toString().intern();
s = null;

Will "foobar" string created by StringBuilder be available to garbage collector? StringBuilder创建的"foobar"字符串是否可用于垃圾收集器?

My doubt is about intern() method, because I am synchronizing some code blocks of application with string based ID. 我怀疑是关于intern()方法,因为我正在使用基于字符串的ID同步一些应用程序的代码块。

Something like this: 像这样的东西:

String id = getUserCurrentId() // this method generates IDs with StringBuider...
synchronized(id.intern()){
    // .....
}

It's a desktop application, with some threads, and each logged user owns a generated ID, at each login process. 它是一个桌面应用程序,带有一些线程,每个登录用户在每次登录过程中拥有一个生成的ID。

I think it will work: 我认为它会起作用:

While even intern ed Strings can be garbage collected (so that you might get different instances of your user id over the lifetime of the JVM), they won't be garbage collected while you are inside of that synchronized block (because then the String is still in use), so it should be stable enough for your purposes. 虽然即使是实际intern字符串也可以被垃圾收集 (因此您可能在JVM的生命周期内获得用户ID的不同实例),但是当您在同步块内部时它们不会被垃圾收集(因为那时字符串是仍在使用中),因此它应该足够稳定以满足您的需要。

Even if you get another instance next time around, that can only mean that the lock was uncontested anyway, so it does not matter. 即使你下次再获得另一个实例,这也只能意味着锁无论如何都是无争议的,所以无关紧要。

But I still would not do this. 但我仍然不会这样做。

How about using a ConcurrentHashMap to get named locks ? 如何使用ConcurrentHashMap获取命名锁

When you call str.intern() you indeed get access to the internal instance of string, ie if this sting already in cache you get reference to this instance. 当你调用str.intern()你确实可以访问字符串的内部实例,即如果这个sting已经在缓存中,你就会得到对这个实例的引用。

When you say: 当你说:

String s = .... /* anything */

you create variable that contains yet another reference to the same string. 您创建的变量包含对同一字符串的另一个引用。 Therefore when you say 因此,当你说

s = null; 

you just put null to that reference. 你只需将null到该引用。 It does not affect the object itself. 它不会影响对象本身。 So, it will be removed by GC if GC decides to remove it. 因此,如果GC决定将其删除,它将被GC删除。 You still can use the source object (that one that was written right to the assignment operator) for synchronization. 您仍然可以使用源对象(直接写入赋值运算符的源对象)进行同步。 Surely synchronized(id.intern()) looks OK. 肯定是synchronized(id.intern())看起来没问题。 Although I have no idea why do you want to do this. 虽然我不知道你为什么要这样做。

BTW re-using objects that have functional meaning in your program for synchronization is a very bad pattern. BTW重新使用在程序中具有功能意义的对象进行同步是一种非常糟糕的模式。 Think about the following scenario. 考虑以下场景。 You are using id.intern() for syncghronization. 您正在使用id.intern()进行同步。 This means that if you ID is for example foo and somebody in other part of the program says 这意味着,如果您的ID是例如foo ,而程序其他部分的某人则说

String s = 'foo'

he gets access to the same object because string literals are cached. 他可以访问同一个对象,因为字符串文字是缓存的。 Now if in other part of the program the following code is written: 现在,如果在程序的其他部分编写以下代码:

String s = 'foo';
.....
synchronized(s) {
    s.notify();
}

and in you wrote in your part of the code 并在你写的部分代码

synchronized(id.intern()) {
    id.wait();
}

probably your wait() will exit! 可能你的wait()会退出! Such unexpected behavior of the program is very hard to debug. 程序的这种意外行为很难调试。 Therefore better practice is to use special objects for locks. 因此,更好的做法是使用特殊对象进行锁定。

声明:本站的技术帖子网页,遵循CC BY-SA 4.0协议,如果您需要转载,请注明本站网址或者原文地址。任何问题请咨询:yoyou2525@163.com.

 
粤ICP备18138465号  © 2020-2024 STACKOOM.COM