// ID 0 represents a null reference // From there we count upwards. IDs are not reused when an object is GCed sclass EphemeralObjectIDs { long idCounter; new WeakValueMap idToObject; Map objectToID = weakIdentityMap(); selfType runnablesReferenceQueue(RunnablesReferenceQueue queue) { idToObject.queue(queue); this; } synchronized long remember(O o) { if (o == null) ret 0; try object objectToID.get(o); long id = ++idCounter; idToObject.put(id, o); objectToID.put(o, id); ret id; } synchronized O get(long id) { if (id == 0) null; ret idToObject.get(id); } synchronized bool wasGarbageCollected(long id) { ret id > 0 && id <= idCounter && get(id) == null; } }