WeakReferences and typical use cases

I am sure every Java programmer albeit a bit advanced would have definitely come across the term “WeakReference”. After hearing this majority of them would have read the Javadoc, which says,

Weak reference objects, which do not prevent their referents from being made finalizable, finalized, and then reclaimed. Weak references are most often used to implement canonicalizing mappings.

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 and all weak references to any other weakly-reachable objects from which that object is reachable through a chain of strong and soft references. At the same time it will declare all of the formerly weakly-reachable objects to be finalizable. At the same time or at some later time it will enqueue those newly-cleared weak references that are registered with reference queues.

Where the weakly reachable is explained by the below set of rules on reachability,

  • An object is strongly reachable if it can be reached by some thread without traversing any reference objects. A newly-created object is strongly reachable by the thread that created it.
  • An object is softly reachable if it is not strongly reachable but can be reached by traversing a soft reference.
  • An object is weakly reachable if it is neither strongly nor softly reachable but can be reached by traversing a weak reference. When the weak references to a weakly-reachable object are cleared, the object becomes eligible for finalization.

So apparently not very clear, this is what I felt when I read it the first time. So this warrants an example at the minimum and that is what I am going to try and post below. 

Typically you would start to think that how would a resource that is already gone, what would you do with that? So as the quote above mentioned that it is used to implement canonicalizing mappings, you would want to handle resource that this depend or are mapped against this resource that just been collected. The most common way of doing this is, subclassing the WeakReference class as I have done for my sample below,

class WeakResource extends WeakReference
{
String mappingToHandle;

public WeakResource(Object weakRes, ReferenceQueue queue, String mapping)
{
super(weakRes,queue);
mappingToHandle = mapping;
}

public void close()
{
System.out.println("Closing the mapping: "+mappingToHandle);
mappingToHandle = null;
}
}

In the above segment in the constructor the referrent and the ReferenceQueue instance are passed to the super class constructor. ReferenceQueue instance is an object where collections show up after the garbage collector has applied the reachability rules. In our case an instance of the object WeakResource would show up after it is deemed weakly reachable. It is important to note that the close method is the one that is used to close the mapped resources or clean up the canonicalizing mappings as the Javadoc mentions.

Next is the reaper thread that needs to pick up things off the RefereceQueue and clean up the mappings, 

class ReferenceReaper extends Thread
{
private ReferenceQueue queueToPoll;

public ReferenceReaper(ReferenceQueue queue)
{
super("RefReaper Thread");
queueToPoll = queue;
setDaemon(true);
}

public void run()
{
WeakResource resource;
while (true)
{
System.out.println("Running");
while ((resource = (WeakResource) queueToPoll.poll()) != null)
{
System.out.println("Found resource");
System.out.println("Mapping is: " + resource.mappingToHandle);
resource.close();
}
try {
Thread.sleep(5 * 1000);
} catch (InterruptedException e) {
// Ignore for sample program
}
}
}
}

In the above code, the reaper is created as a daemon thread looking at appearances of WeakResource objects on the reference queue. It wakes up at regular intervals and calls the poll() method on the reference queue whose javadoc is like below,

Polls this queue to see if a reference object is available. If one is available without further delay then it is removed from the queue and returned. Otherwise this method immediately returns null.

So when this reaper thread runs it will retrieve all items that show up in the queue and call close to clean up the mapped resources

Finally, putting it all together. 

public class WeakRefImpl
{
private List<WeakResource> weakResources;
private ReferenceQueue queue;

public WeakRefImpl()
{
weakResources = new ArrayList<WeakResource>();
queue = new ReferenceQueue();
new ReferenceReaper(queue).start();
}

public void createResources()
{
Object []resources = new Object[]{new Object(),new Object(),new Object(),new Object(), new Object()};
int i = 0;
String mapping = "map - ";
for(Object res : resources)
{
WeakResource weakRes = new WeakResource(res,queue,mapping + i);
weakResources.add(weakRes);
i++;
}
resources = null;
}

public static void main(String []args) throws Exception
{
WeakRefImpl impl = new WeakRefImpl();
impl.createResources();
//Try gc'ing. This is only for sample, usually no one should call this and just let JVM do its job and then gather the references
System.gc();
Thread.sleep(1000*1000);
}

}

In the above segment, in the createResources method the WeakResource object is created and added to a list. Then right at the end of the method the resources array is nullified which makes is eligible for garbage collection.

FInally in the main method call the createResources method and the explicitly call the GC for demo purposes. Ideally this will never be done and when the GC happens all the WeakResource objects will queue up at the ReferenceQueue and mapped resources would get closed. I put in a big sleep right at the end to let the program finish collecting the resources.

When all the above pieces are put together and run the output in my machine would like this,

Running
Running
Found resource
Mapping is: map - 0
Closing the mapping: map - 0
Found resource
Mapping is: map - 4
Closing the mapping: map - 4
Found resource
Mapping is: map - 3
Closing the mapping: map - 3
Found resource
Mapping is: map - 2
Closing the mapping: map - 2
Found resource
Mapping is: map - 1
Closing the mapping: map - 1

This could be different in your machine and different on my machine if I run again as the order GC puts them on the reference queue would change.

Some of the common use cases that I have used them is for implementing JDBC connection to JDBC statement mappings. All statements would need to know about connections and hence would have to have strong reference to connection, but the connection would only need to have a weak reference. That way, when the statement goes away, the connection can do the cleanup or handle the case for Statement pooling. Other use is that for determining leaks during diagnostic runs, where one can use the same concept of closing things with weak mappings when they were not explicitly closed. This would help determine leaks of un-closed resources.

Hope this example clarifies typical use cases for WeakRefernce and makes things more clear !!! 

Happy Coding 🙂

Advertisements

Working with Java Collections – element removal, for-each and Iterators

I am sure many of you would have come across the use case of having to remove entries from a collection into which you had previously added data. There could be a variety of use cases where this pops up, a very common one is the case of a cache clean up or a pool clean up.

In either of the two use cases above, entries would have been added / accessed when needed and typically programmers write clean up tasks that loop over such structures to evaluate a policy that they would have set at creation time. If the entry in the pool / cache meets the policy constraints its retained, if it doesn’t its evicted. Sounds a simple enough problem to solve.

The advent of for-each loops structures in Java 5 came as a blessing, especially considering the ugly iterator code that people had to write before. The readability and maintainability definitely increased. But is it a good idea to replace all iterator code with the for-each loop ?

The answer is no. There are a few cases where it cannot and should not be replaced. In some cases the ramifications are visible and obvious, in other cases it is not as obvious.

DISCLAIMER : It may not be the best way to write code, but is only for demonstration of the use case 🙂

To illustrate one such use case, take a look at the code snippets below,

    public void populateCollection()
    {
        for (int i = 0 ; i < 20 ; i++)
        {
            listOfStrings.add("String-"+i);
        }
        System.out.println("Size of the collection is: "+listOfStrings.size());
    }

The above code snippets, adds elements to an ArrayList.

The below snippet tries to remove the 10th element from the list while iterating over it.

public void removeItem()
    {
        // Remove item number 10
        // Expect it to work ?
        int counter = 0;
        try {
            for (String entry : listOfStrings) {
                System.out.println("Entry number " + (counter + 1) + " is : "
                        + entry);
                if (counter == 9) {
                    System.out.println("Removing Entry : " + entry);

                    listOfStrings.remove(entry);

                }
                counter++;
            }
        } catch (ConcurrentModificationException e) {
            System.out.println("Oops did not expect this");
            e.printStackTrace();
        }
    }

Will this work ? Why not would be many people’s reaction.  Programmers may think why is this sample code even trying to catch a runtime exception? Again, this is to demonstrate that this exception is indeed thrown !!!

Surprised? You really should not be, because the whole problem is, there is an implicit Iterator here that is traversing the collection and you are going a removing an entry from the collection via a backdoor channel. Since these kind of collections have what are called fail-fast iterators, you will get a ConcurrentModificationException like below.

java.util.ConcurrentModificationException
    at java.util.ArrayList$Itr.checkForComodification(Unknown Source)
    at java.util.ArrayList$Itr.next(Unknown Source)
    at CollectionTester.removeItem(CollectionTester.java:XXX)

How do you solve this? Use the good old iterator traversal  and remove it using the Iterator, like below.

public void removeProperly()
    {
        int counter = 0;
        
        Iterator<String> listItr = listOfStrings.iterator();
        while(listItr.hasNext())
        {
            String entry = listItr.next();
            System.out.println("Entry number "+(counter+1) +" is : "+entry);
            if(counter == 9)
            {
                System.out.println("Removing Entry Properly : "+entry);
                try
                {
                    listItr.remove();
                }
                catch (ConcurrentModificationException e)
                {
                    System.out.println("Oops did not expect this");
                    e.printStackTrace();
                }
            }
            counter++;
        }
    }

This will work as expected and remove the entry. Having a try – catch block just to ensure everything is fine. This demonstrates a pitfall that programmers should avoid while replacing iterators with the for-each loop construct.

This has one more caveat though, the concurrent collections in the java.util.concurrent package have something called a weakly-consistent iterator whose definition is like this, ” iterator that will never throw  ConcurrentModificationException and guarantees to traverse elements as they existed upon construction of the iterator, and may (but is not guaranteed to) reflect any modifications subsequent to construction”. So its a call that a programmer has to take while dealing with these collections, but it is probably better to stick with the usual iterator way.

Hope this entry helps people who have been hit by nasty, unexpcted ConcurrentModificationException  that is giving them nightmares !!!