简体   繁体   中英

Cleaning up resources associated with weak reference

In one program I need to store weak references in a certain storage engine (an embedded Prolog database in fact). To keep the explanation simple, such storage engine can be considered (in the context of this question) as a collection of weak references.

I need to warranty that weak references are going to be retracted from the storage engine as soon as the reference is reclaimed. In other words, it should not be possible to access a weak reference from the engine if its get() method already returns null.

I currently implemented this by means of a ReferenceQueue .

The following code extends a weak reference by means of a adding a cleanUp() method (which invokes a cleaning task that deletes the weak reference from the engine):

public class MyWeakRef<REF_TYPE> extends WeakReference<REF_TYPE> {

    MyWeakRef(REF_TYPE referent, ReferenceQueue<REF_TYPE> referenceQueue, Runnable cleaningTask, ...) {
        super(referent, referenceQueue);
        this.cleaningTask = cleaningTask;
        ...
    }

    void cleanUp() {
        cleaningTask.run();     
    }
    ...
}

The code below shows how the references are cleaned in a separate thread that takes reclaimed references from a ReferenceQueue and invokes their cleanUp() method:

public class WeakReferencesCleaner extends Thread {

    private static WeakReferencesCleaner referencesCleaner = new WeakReferencesCleaner(new ReferenceQueue<Object>());

    public static WeakReferencesCleaner getWeakReferencesCleaner() {
        return referencesCleaner;
    }

    public synchronized static void startWeakReferencesCleaner() {
        if(!referencesCleaner.isAlive())
            referencesCleaner.start();
}

    private ReferenceQueue<?> referenceQueue;

    public WeakReferencesCleaner(ReferenceQueue<?> referenceQueue, int priority) {
        this.referenceQueue = referenceQueue;
        this.setDaemon(true);
    }

    public ReferenceQueue<?> getReferenceQueue() {
        return referenceQueue;
    }

    @Override
    public void run() {
        while(true) {
            try {
                MyWeakRef<?> ref = (JTermRef<?>) referenceQueue.remove();
                try {
                    ref.cleanUp();
                } catch(Exception e) {
        ...
            }
                } catch (InterruptedException e) {}
            }
    }
}

Although in my tests this is working fine, I found out the following in the documentation of the WeakReference class:

Suppose that the garbage collector determines at a certain point in time that an object is weakly reachable. At that time it will atomically clear all weak references to that object ...At the same time or at some later time it will enqueue those newly-cleared weak references that are registered with reference queues.

Therefore, between the time the reference is invalidated and the method cleanUp() is executed another thread could query the engine and still find the invalidated reference.

My question is: How I could warranty in a multi threading context that an invalidated reference is never returned by my engine ?

You should adjust your requirements. A code dealing with a List of WeakReference s is low level enough to deal with the fact that a WeakReference 's get() method might return null . This code dealing with the List is responsible to provide a higher level API which shows neither WeakReference s nor spurious null values. The class WeakHashMap gives a blue print of such a design. The code using a WeakHashMap does not have to deal with possible in-between garbage collection. The get() method of WeakHashMap does internally.

Note that even if there was no time between the collection and enqueuing there was no guaranty for not seeing null values from the get() method. The point is that you are cleaning up in another thread so there is no guaranteed timing anyway. A Reference being on the queue does not imply that your cleanup thread polling that queue gets CPU time immediately. It would depend on the system's thread scheduling whether your cleanup thread runs timely before the thread reading the List can get the affected element.

The technical post webpages of this site follow the CC BY-SA 4.0 protocol. If you need to reprint, please indicate the site URL or the original address.Any question please contact:yoyou2525@163.com.

 
粤ICP备18138465号  © 2020-2024 STACKOOM.COM