Re: Data structure to keep things in memory
On 28/11/10 09:07, ClassCastException wrote:
You need to do something a little bit more complicated: have an RTS
object with the actual statistics, plus an RTSHandle object for each RTS
object that holds the RTS object with an ordinary (strong) reference,
plus a Map<WeakReference<RTSHandle>,RTS> from WeakReferences to the RTS
objects. When a new RTS is created, the factory method creates an
RTSHandle as well, and a WeakReference on that handle, and puts a mapping
from the WeakReference to the RTS into the map as well as returning the
handle. The rest of your program uses the RTSHandle to access the RTS and
add statistics, eventually losing all strong references to the RTSHandle.
When this happens, the RTSHandle becomes weakly reachable as the only
remaining reference to it is the WeakReference in the map. The
WeakReference is enqueued. The queue polling thread finds it and uses it
as a key in the map. Since WeakReference doesn't override Object's
identity-based equals and hashCode this works even with the referent GCd.
It accesses the RTS via the map, does its thing, and then removes the map
entry for that RTS, allowing the RTS and the WeakReference to be GCd.
I've done something similar, except that I extended WeakReference so
that it contained a strong reference to the base object (RTS in this
case), rather than having the Map<Ref,RTS>. The WeakReference class
also implemented Runnable, so all the polling thread has to do is cast
the returned reference to Runnable and invoke it. In the OP's case, it
would look something like this:
// I'd make RTS an interface...
public interface RTS { ... }
// ...then make a (private) class implement it.
class RTSImpl implements RTS { ... }
// RTSHandle is just a proxy onto another RTS.
class RTSHandle implements RTS {
final RTS base;
RTSHandle(RTS base) { this.base = base; }
// all methods just call onto base
}
class RTSUser extends WeakReference<RTSHandle> implements Runnable {
final RTSImpl impl;
RTSUser(RTSHandle handle,
ReferenceQueue<? super RTSHandle> queue,
RTSImpl impl) {
super(handle, queue);
this.impl = impl;
}
void run() {
finishWith(impl);
}
}
ReferenceQueue<Object> queue = new ReferenceQueue<Object>();
// The factory method
public RTS getRTS() {
RTSImpl impl = new RTSImpl();
RTSHandle handle = new RTSHandle(impl);
RTSUser user = new RTSUser(handle, queue, impl);
return handle;
}
void finishWith(RTSImpl impl) {
...
}
// Call this in a loop.
void expireOneRef() throws InterruptedException {
Runnable action = (Runnable) queue.remove();
action.run(); // Calls finishWith, if (action instanceof RTSUser).
}