A Look At Java’s Callable Interface Part 002

As I mentioned before, I am going through Programming Concurrency on the JVM by Venkat Subramaniam. I am looking at the Callable interface. He uses it a few times in chapter 2. I will go over some code I posted last time.

The two files I will go over are CallableWorker and ForwardCallableRunner. There are a few things in the code that are not relevant to concurrency, but still have use. I put in the ForwardCallableRunner.setIterations which will set the number of iterations a loop will run by using a system property, or set a default value if none is provided. I also put in some logging statements and calls to Thread.sleep() to get a better idea of when things are called.

The class that does the concurrent magic is CallableWorker. It implements the java.util.concurrent.Callable interface. It is part of the concurrency APIs that were introduced in JDK 5. It is similar to the java.lang.Runnable interface that has been part of the JDK since the very beginning. The main difference is that Callable can return a value and Runnable cannot. Developers would have to create additional methods to check if their Runnable.run() method had completed. Dr S says that we should use the newer APIs and not bother with the older stuff.

The only method defined by Callable is the call() method. It takes no arguments, and returns an object. If you are returning a Java primitive (like an int or double), you must use one of the wrapper classes in java.lang, like java.lang.Double. You implement the call() method, but you never actually call it. Callable uses generics, so in your class declaration you put:

SomeCallable implements Callable <ReturnTypeOfCall>

 

That type should be the same as the type of whatever the call() method returns.

I added a few parameters to the constructor. A lot of examples online that I saw (including the original that I got this from by Lars Vogella) do not use a lot of data. They just increment a variable in a loop. do some simple math, and return the result. If you want to add data to your class to work on, you could either add it via the constructor, or another method, or create the Callable inline, as Dr S does in his examples. I would guess that adding it in the constructor would be better for thread safety. But ulitimately, I just do some simple summing, like most other examples.

The class that creates and uses the Callables is ForwardCallableRunner. I also made a BackwardCallableRunner. They both create some Callables, which sum some numbers in loops. In ForwardCallableRunner, the numbers send to the constructors for CallableWorker increase in the loop, and in BackwardCallableRunner they decrease.

The first thing you need to do when using a Callable is to create a thread pool. The JDK 5 API gives you some classes to do that.

Use java.util.concurrent.Executors to create a thread pool. I use the method Executors.newFixedThreadPool with an integer argument for the size of the thread pool. This will return an instance of java.util.concurrent.ExecutorService.

Executors.newFixedThreadPool is overloaded. You could also call it with an addition argument, which is a class implementing the java.util.concurrent.ThreadFactory interface. There are also a couple of methods that make thread pools of dynamic size: Executors.newCachedThreadPool. You can use the Executors.newFixedThreadPool without specifying a ThreadFactory. There are a couple of other libraries that do implement or return an instance of java.util.concurrent.ThreadFactory: BasicThreadFactory in Apache Commons Lang, and  ThreadFactoryBuilder in the Google Guava library. I have not tried them, so I do not know what they give you beyond what the default implementation gives you.

The next step is to create an instance of  java.util.concurrent.Future, or a list of them. It must be of the same type as the Callable you created before.

The next part of the example is in a loop. In each iteration, I created a Callable, and I sent it as an argument in a call to the method java.util.concurrent.ExecutorService.submit. This will return a java.util.concurrent.Future, which will hold the result of our Callable. The Callable.call method starts when the ExecutorService.submit method is called. (I inferred this from the examples, but I wanted some verification; this is what led me to put in the logging statements.) I then add the Future that was just created to my list of Future objects.

Lastly, I create a for loop to cycle through the Future objects. This shows the next step in our Callable/Future lifecycle. To get the return value of the Callable.call method, you call Future.get. The documentation says that it will wait if the result is not ready yet. This is why I made an example that counts upwards through the number of iterations and one that starts at the iteration number and counts to 0. Since my CallableWorker.call method also does some sleeping, the class with the highest number should take longer. I wanted to see if the for loop with the call to Future.get would actually wait if the next Callable.call was not done yet. Since I got the same result in both classes, I assume that it did.

The last step is to call ExecutorService.shutdown().

Most of the examples are like the one that I worked with: They call ExecutorService.submit for each Callable. Dr S creates a java.util.List of Callable objects, and starts them off by calling ExecutorService.invokeAll. He also creates his Callable objects inline, and does not have a separate Something.java file for them.

So, to summarize, here are the steps to using Callable:

1. Create a class that implements the java.util.Callable interface. (This step could come later.)

2. Create a thread pool by calling java.util.concurrent.Executors.newFixedThreadPool to return an instance of java.util.concurrent.ExecutorService

3. Create a list with type of java.util.concurrent.Future.

4. Call ExecutorService.submit, sending it a Callable object. This will create a Future object, which you add to your list of Future objects.

5. Get the result of all of your Callable.call methods by iterating through your list of Future objects, and calling Future.get on each one.

6. Clean up by calling ExecutorService.shutdown.

Dr S does this slightly differently:

1. Create a list of inline objects that implement the java.util.Callable interface.

2. Create a thread pool by calling java.util.concurrent.Executors.newFixedThreadPool to return an instance of java.util.concurrent.ExecutorService

3. Create a list with type of java.util.concurrent.Future, and instantiate it with a call to ExecutorService.invokeAll. The paramter of ExecutorService.invokeAll is the list of Callable objects created in step 1.

4. Get the result of all of your Callable.call methods by iterating through your list of Future objects, and calling Future.get on each one.

5. Clean up by calling ExecutorService.shutdown.

His way has fewer steps, and fewer lines of code. But honestly I prefer the way most examples do it. I think it is clearer. Doing too much inline looks a bit noisy and crowded to me.

 

Image from a 12th-century manuscript housed at the Bamberg State Library (Wikipedia page here), manuscript description here, citation link here, image assumed allowed under Fair Use.