I don't think there is a good way to do it. There are a few problems:
The cleaning of stale entries from the WeakHashMap
is an internal mechanism that involves a ReferenceQueue
that is private to the implementation. You would need to break encapsulation to access the queue
field.
OK that is possible, but you would be making your code Java version specific ... in theory.
There is no good way for something other than WeakHashMap
itself to inspect the queue. ReferenceQueue
only provides three public operations: poll()
, remove()
and remove(time_out)
. These will all remove an element from the queue (if or when there is one). But if anything other than the WeakHashMap
removes an element, that element won't be processed.
This effectively means that you cannot detect when there is stuff on the queue without "breaking" it.
OK so you could break abstraction on the ReferenceQueue
as well to access its head
field.
Even if you do the above, you would still need to poll the ReferenceQueue.head
field to detect when the queue becomes non-empty and empty again.
The code in WeakHashMap
that processes the queue does not run spontaneously. (There is no cleaner thread.) It actually runs when something performs an operation (e.g. get
, put
, size
, clear
and so on) on the WeakHashMap
. The details are liable to be version specific.
This means the "event" that your code is trying to detect is only going to happen when you call get
. So if you only want to call get
after the entry has been removed, you have a "loop" in the temporal dependencies.
Finally, it is not guaranteed that calling System.gc()
will run immediately, (or at all), or that it will detect that given unreachable object is unreachable1. And even if it does detect this, it is not guaranteed that the WeakReference
will be broken in a timely fashion.
So you should not code your application to depend on those things ... via predictable cleaning of the map. (And if the real use-case for this just unit testing, I don't think this is worth spending the time on this. The sleep
workaround is fine ... assuming it is reliable enough.)
1 - For example, if the object has been tenured and the System.gc()
call only triggers an minor collection, then the object would not be detected as unreachable.