RSS Feed
Download our iPhone app
Browse DevX
Sign up for e-mail newsletters from DevX


Building Multithreaded Java Applications : Page 6

The Java concurrency utilities released in Java 5.0 simplified the development of multithreaded applications through their simple-to-use but robust and powerful API.


Exception Handling and Task Result

You can retrieve the task result using either the Future.get() or the Future.get(long timeout, TimeUnit unit) method. The no-argument method blocks other tasks until the task completes by normal execution, by cancellation, or by throwing an exception. Use this method with caution, because it will wait indefinitely for a task to complete. The Future.get() method with a timeout parameter is more useful because it will cause a method to return after a specified period of time:

for (Future<Integer> f : futurList) {
  try {
    Integer result = f.get(1000, TimeUnit.MILLISECONDS);
    Logger.log(f + " result. Processed orders " + result);
  } catch (InterruptedException e) {
    Logger.error(e.getMessage(), e);
  } catch (ExecutionException e) {
    Logger.error(e.getCause().getMessage(), e);
  } catch (TimeoutException e) {
    Logger.error(e.getMessage(), e);
  } catch (CancellationException e) {
    Logger.error(e.getMessage(), e);

  // to avoid printing completed tasks, you may want to remove
  // the completed task from futureList here

The Future.get() method throws different exceptions to give an exact reason for each task failure:

  • InterruptedException is thrown if a thread is interrupted while waiting for computation results.
  • TimeOutException is thrown if a result cannot be retrieved in the specified period of time.
  • CancellationException is thrown if computation is cancelled.
  • ExecutionException is thrown if a task computation fails by throwing any exception, including runtime exceptions. This ensures that the executor threads will not be terminated due to an exception in task execution. The side effect of this behavior is that in application scenarios where you want to propagate a task runtime exception, you need to retrieve the runtime exception from ExecutionException and throw it again.

Putting the Pieces Together

The OrderProcessorMain class (see Listing 3) uses all the concepts discussed in the previous sections. In particular, the main() method performs the following steps:
  1. Creates and configures the CustomThreadPoolExecutor object
  2. Creates and submits the OrderProcessorCallable tasks
  3. Populates the order-blocking queue with OrderVO objects
  4. Prints processor status at regular intervals until the order-blocking queue is empty
  5. Shuts down the thread pool executor
  6. Prints the task result after task completion

To see the sample application in action, just run the OrderProcessorMain.main(String[] args) method. For convenience, the source code download provided with this article can be imported as an Eclipse project.

Anil Kumar Garg works as a senior technical architect at the J2EE Center of Excellence at Infosys Technologies Limited, a global leader in IT and business consulting services. He has more than 10 years of software industry experience.
Email AuthorEmail Author
Close Icon
Thanks for your registration, follow us on our social networks to keep up-to-date