这个blog post演示了一种实现每个字符串id惯用法的互斥的方法。使用的字符串ID表示HttpSession ID。
为什么我们需要两次调用put?
public Mutex getMutex( String id )
{
Mutex key = new MutexImpl( id );
synchronized( mutexMap )
{
WeakReference<Mutex> ref = mutexMap.get( key );
if( ref == null )
{
mutexMap.put( key, new WeakReference<Mutex>( key ) );
return key;
}
Mutex mutex = ref.get();
if( mutex == null )
{
mutexMap.put( key, new WeakReference<Mutex>( key ) );
return key;
}
return mutex;
}
}
答案 0 :(得分:4)
WeakHashMap中的值对象由普通的强引用保存。因此,应该注意确保值对象不直接或间接地强烈引用它们自己的密钥,因为这将防止密钥被丢弃。注意,值对象可以通过WeakHashMap本身间接引用它的键;也就是说,值对象可以强烈地引用一些其他关键对象,其关联值对象又强烈地引用第一值对象的关键字。处理此问题的一种方法是在插入之前将值本身包装在WeakReferences中,如:m.put(key,new WeakReference(value)),然后在每次get时解包。
答案 1 :(得分:2)
1 - @Loop有good answer。
2 - 假设条目包含WeakReferences,第二个put
是必需的,因为在执行到达行之前可能会收集WeakReference
:
Mutex mutex = ref.get();
在这种情况下:
map
Mutex mutex = ref.get();
答案 2 :(得分:1)
我会说WeakReference
只是因为需要引用http会话id而使用。您无法始终100%确定您收到会话结束的通知,从而导致地图不断增长。
第一次拨打电话是因为地图不包含您的密钥。第二次是因为地图确实包含了密钥,但引用不再存在。
答案 3 :(得分:1)
Loop和Bruno Conde几乎涵盖了它,但自从我写了这段代码......
设计目标是避免让用户调用释放机制 - 当用户不再引用它时,互斥锁有资格进行垃圾收集。
为什么我们需要包装WeakReference 在Mutex实例周围?
地图是WeakHashMap:
private final Map mutexMap = new WeakHashMap();
此映射用于保留对互斥锁的引用,但如果对键和值使用相同的对象,则该对象不符合垃圾回收的条件。的Javadoc:
实施说明:价值对象 在WeakHashMap中是普通的 强烈的参考。因此应该谨慎 采取以确保价值对象 不强烈提及自己的钥匙, 直接或间接地,因为 这将阻止密钥 丢弃。注意一个值对象 可以间接引用其关键通道 WeakHashMap本身;这是一个 价值对象可能强烈提及 一些其他关键对象 反过来,价值对象强烈地指 到第一个值对象的键。 解决这个问题的一种方法是包装 重视自己 插入前的WeakReferences,如 in:m.put(key,new WeakReference(value)),然后 解开每一个。
不是吗 最好只创建一个Map 字符串 - &gt;互斥?
该String值何时被垃圾收集?是否每次都传递相同的引用?是否intern()被调用了吗?如果我打电话给实习生,那么String会活多久?如果String是键,则在不需要保留对它的引用之后,互斥锁可能没有资格进行垃圾收集。
为什么我们需要两次调用put?
有两种情况需要处理,直到该方法能够在地图中获得对互斥锁的强引用:
put 只会被调用一次;该方法在之后立即返回。
(WeakReference可以在第二次使用中重复使用,但我不认为这将是一个重大改进。)
当然,如果有人可以在代码中找到错误,请告诉我,我会很乐意纠正它。此外,单元测试尝试检查实现是否泄漏,因此可以随意修改代码并查看运行测试时会发生什么。