Tag Archives: guava

Guava: Using CheckedFuture

In this post, I want to discuss another class from Google Guava. Today, it will be CheckedFuture. Let’s first see the JavaDoc of the class:

A CheckedFuture is an extension of Future that includes versions of the get methods that can throw a checked exception and allows listeners to be attached to the future. This makes it easier to create a future that executes logic which can throw an exception.

Implementations of this interface must adapt the exceptions thrown by Future#get(): CancellationException, ExecutionException and InterruptedException into the type specified by the E type parameter.

This interface also extends the ListenableFuture interface to allow listeners to be added. This allows the future to be used as a normal Future or as an asynchronous callback mechanism as needed. This allows multiple callbacks to be registered for a particular task, and the future will guarantee execution of all listeners when the task completes.

From this explanation, we can conclude two things about CheckedFuture:

  1. It extends ListenableFuture which has been discussed in this article.
  2. It aims to simplify exception management of Future.

Let’s look at code. Normally, if Future execution is cancelled because the inner-process throws exception, it will wrap the exception in a ExecutionException. So, our code will looks like something like this.

try {
	task.get();
} catch (ExecutionException e) {
	if (e.getCause()
			instanceof ApplicationException) {
		throw (ApplicationException) e.getCause();
	}
	throw new ApplicationException(e);
} catch (InterruptedException e) {
	throw new ApplicationException(e);
} catch (CancellationException e) {
	throw new ApplicationException(e);
}

A lazy programmer (don’t we all are lazy)? will write that like this:

try {
	task.get();
} catch (Exception e) {
	if (e.getCause()
			instanceof ApplicationException) {
		throw (ApplicationException) e.getCause();
	}
	throw new ApplicationException(e);
}

The same code can be implemented using CheckedFuture like this:

Function<Exception, ApplicationException> mapper =
	new Function<Exception, ApplicationException>() {

	@Override
	public ApplicationException apply(
			Exception from) {
		if (from.getCause() instanceof ApplicationException) {
			throw (ApplicationException) from.getCause();
		}
		throw new ApplicationException(from);
	}
};
CheckedFuture<String, ApplicationException> checkedTask =
	Futures.makeChecked(task, mapper);

checkedTask.checkedGet();

So I guess you’ll say: ‘but the code is longer than the original’. It’s true that in this example the code seems to be longer. In fact, if your case is so simple like this, I’ll suggest you to just use the original version.

This is pretty much same case of using functional-like Java coding style. It’s overkill if the case is so small. The advantage can only be seen once your code grows bigger.

In this CheckedFuture case, one example where using it will give you huge benefit is when you start sending the Future/CheckedFuture around and the get()/checkedGet() is executed in many places. That time, you’ll see that wrapping each call will try catch is annoying and this is where CheckedFuture-based solution will shine.

Guava: Using ListenableFuture

Google Guava has many interesting classes which we can use on our application. The ones from collection package have been already used by many developers and this blog has tutorial on how to use the computing map.

I want to move to the other package. This one is com.google.common.util.concurrent, specifically I want to introduce ListenableFuture. The documentation of the class is as follow:

This interface defines a future that has listeners attached to it, which is useful for asynchronous workflows. Each listener has an associated executor, and is invoked using this executor once the Future’s computation is Future#isDone() complete}. The listener will be executed even if it is added after the computation is complete.

Consider following example. If we have task T1, T2, and T3. T2 can only be done when T1 is finished and T3 can only be done once T2 is ended. The diagram below shows the dependency.

The easiest solution without any concurrency is of course to just run each task one after another. But consider that we have 5 set of these operation. Without thread we can end up with serial solution depicted by the following picture.

ListenableFuture made it easy to create the concurrent version of the solution.

This is a code example of this solution which will print “1”, then pause for a second before printing “2”, and another stop for 1 second before finally printing “3”. Note that ListenableFutureTask extends ListenableFuture.

import java.util.concurrent.Callable;
import java.util.concurrent.ExecutorService;
import java.util.concurrent.Executors;

import com.google.common.util.concurrent.ListenableFutureTask;

public class TestListenableFuture {

	static class SimpleTask extends
			ListenableFutureTask<Void> {
		SimpleTask(final String message) {
			super(new Callable<Void>() {

				@Override
				public Void call() throws Exception {
					System.out.println(message);
					Thread.sleep(1000);
					return null;
				}
			});
		}
	}

	public static void main(String[] args) {
		ListenableFutureTask<Void> task1 =
			new SimpleTask("1");
		ListenableFutureTask<Void> task2 =
			new SimpleTask("2");
		ListenableFutureTask<Void> task3 =
			new SimpleTask("3");

		ExecutorService exec =
			Executors.newSingleThreadExecutor();
		exec.submit(task1);
		task1.addListener(task2, exec);
		task2.addListener(task3, exec);

		try {
			Thread.sleep(10000);
		} catch (InterruptedException e) {
		}
		exec.shutdown();
	}
}

Pretty easy, isn’t it? And we can probably extend this solution to create a full workflow framework solution.

UPDATE: Remember that the API is still in Beta version. I’ll try to update it once the release version is released

Computing Map on Google Collections

2009-11-13_1134

Google always makes interesting projects. My toy nowadays is Google Collections. I don’t think I need to reintroduce it as it has been nicely covered on several blog posts:

Of course, two videos from GTUG are also nice.

Now I want to discuss one functionality from Google Collections which is not really covered by those previous articles. This functionality is called Computing Map. No.. no.. you won’t find a class with such name in their Javadoc.

It is basically a map, where the keys are parameters for a calculation, and the values are results of the calculation. Probably you ever faced such scenario where you need to do a lot of computations using complex algorithm? Fortunately, says that many of those calculations are done using the same parameters. So, instead of doing the same operation over and over again, would it be better to just cache the result and using it later?

That is basically the idea and you can even implement it without using Google Collections. You can code something like this:

private final Map<Parameter, Result> cache = new HashMap<Parameter, Result>(100000);

public Result getResult(Parameter p) {
        if (!cache.containsKey(p)) {
            prepareCache(p); // the complex calculation
        }

        return cache.get(p);
}

Easy, yes?

But wait… there is a problem with such code. First, how if two calculations are done at almost the same time? You won’t get the wrong result, but the code will still do the calculation twice due to thread problem. No easy solution for such case, double-checked locking is just failed.

And more problems may arise. With time it is possible that there are so many parameters used and your Map will grow without limit. This is standard problem for any cache implementation and using soft reference or any third-party cache implementation may solve the problem.

At the end, our solution is not just so simple anymore.

Here Google Collections may help us. The MapMaker is a very powerful factory-class that allow you to combine features of a Map you can think of. Need a Map with soft reference key and weak reference value? Need a map with strong key and soft reference value? MapMaker will allow you to do that… the easy way.

And it provides us with a Computing Map. A computing map is created with MapMaker by calling the method ‘makeComputingMap’ and defining a function that will transform Parameter to Result.

Our example before will be something like this:

private final Map<Parameter, Result> cache;

public Cache {
    cache = new MapMaker().makeComputingMap(new Function<Parameter, Result>() {

            @Override
            public Result apply(Parameter from) {
                return prepareCache(from);
            }
        });
}

public Result getResult(Parameter p) {
        return cache.get(p);
}

That is basically all. The documentation of the method is like this:

Builds a map that supports atomic, on-demand computation of values.
Map#get either returns an already-computed value for the given key,
atomically computes it using the supplied function, or, if another thread
is currently computing the value for this key, simply waits for that thread
to finish and returns its computed value. Note that the function may be
executed concurrently by multiple threads, but only for distinct keys.

If an entry’s value has not finished computing yet, query methods
besides get return immediately as if an entry doesn’t exist. In
other words, an entry isn’t externally visible until the value’s
computation completes.

Map#get on the returned map will never return null. It
may throw:

  • NullPointerException if the key is null or the computing
    function returns null

  • ComputationException if an exception was thrown by the
    computing function. If that exception is already of type
    ComputationException, it is propagated directly; otherwise it is
    wrapped.

Note: Callers of get must ensure that the key
argument is of type K. The get method accepts
Object, so the key type is not checked at compile time. Passing an object
of a type other than K can result in that object being unsafely
passed to the computing function as type K, and unsafely stored in
the map.

If put is called before a computation completes, other
threads waiting on the computation will wake up and return the stored
value. When the computation completes, its new result will overwrite the
value that was put in the map manually.

This method does not alter the state of this MapMaker instance,
so it can be invoked again to create multiple independent maps.

So you’ll get synchronization freely. And best of all, the synchronization doesn’t lock the whole Map, only threads that access the same key.

But there is still a problem with that code… It’s still using strong reference for both keys and values. That’s the default implementation if you don’t specify anything in the MapMaker. Your map will still grow limitless and you will eventually get an OutOfMemoryException.

Well, it’s easy… you can just add a call (softValues) to the creation.

private final Map<Parameter, Result> cache;

public Cache {
    cache = new MapMaker().softValues().makeComputingMap(new Function<Parameter, Result>() {

            @Override
            public Result apply(Parameter from) {
                return prepareCache(from);
            }
        });
}

public Result getResult(Parameter p) {
        return cache.get(p);
}

Now you have a proper implementation of computing map. The values and keys will be hold as long as you have enough memory, but once it need more memory, GC will remove the entries from the Map. Your application will need to calculate the complex calculation again but I think it’s the best achievement of what we can get. Of course you can increase the JVM memory easily anytime you want.

Note that you don’t want to use softKeys. Look at the Javadoc of softKeys.

Note: the map will use identity ({@code ==}) comparison
to determine equality of soft keys, which may not behave as you expect.
For example, storing a key in the map and then attempting a lookup
using a different but {@link Object#equals(Object) equals}-equivalent
key will always fail.

Hmm… that means that your key will be considered equals if it is the same object. If you recreated the Parameter with the same value and even if you override the equals and hashCode correctly, you will not using the pre-computed value. On the other hand, using just softValues is enough, because once the values is GC-ed, the keys will be removed as well. See this bug entry for more information: http://code.google.com/p/google-collections/issues/detail?id=250 or this dialog in the groups: http://groups.google.com/group/google-collections-users/browse_frm/thread/8e4bd19f5cfa9adb/24e9d9de34fadb6f?lnk=gst&q=soft+reference+identity#24e9d9de34fadb6f.

And if you still think that you have a use case for equality soft reference, I have a patch to the MapMaker you can use. It’s not nice and pretty hacky, but it works as far as I can say. I personally don’t use it anymore but maybe I will in the future (if I find a strong use case for that, which I doubt).

MapMaker.java