目前社区中有几个应用使用了类似Locker的代码,基本上都是从消息系统引擎中提取出来的,唯一的区别在于消息中使用的Locker中的id的类型为long,而id在作为键被put进Map时被JVM自动转换成了Long,因此避免了 WeakHashMap中的键被值所引用。而如果使用String作为id则会因为Map中的值引用了自己的键,导致JVM无法根据键是否还被引用而清除 WeakHashMap中的entry。可通过下面的测试代码,清楚的观察到结果。
public class Locker {
private static WeakHashMap<String, Locker> lockerMap = new WeakHashMap<String, Locker>();
private final String id;
private Locker(String id) {
this.id= id;
}
public synchronized static Locker acquire(String id) {
Locker locker = lockerMap.get(key);
if (locker == null) {
locker = new Locker(id);
lockerMap.put(id, locker); //问题代码,导致了entry.key == entry.value.id
//lockerMap.put(new String(id), locker); //这是一种修改方式,保证了WeakHashMap中的key,没有被value直接或间接所引用
}
return locker;
}
public String getId() {
return this.id;
}
public static int getSize() {
return lockerMap.size();
}
}
public class LockerTest extends TestCase {
public void testLocker() {
for (int i = 0; i < 10000000; i++) {
Locker.acquire("abc" + i);
if (i % 10000 == 0) {
System.gc();
System.out.println(Locker.getSize()); //输出垃圾回收后的Map的Size
}
}
}
}
责任编辑:小草