Saturday, February 5, 2011

Communication between Java threads : exception propagation example

In this article, I'll show you how a child thread can report an exception to its parent thread.
This mechanism prove to be very useful and convenient when the parent thread needs to take some action whenever one of its child thread fails to execute to its completion.

In the following example, a TaskManager instance acts as the main thread and a Task instance, as its child thread. The TaskManager launches a Task and the latter will throw an Exception. If we want the main thread to be notified when an exception is thrown in its child thread, one solution is to have it implement the ExceptionListener interface and to have the child thread class get a reference to the instance of ExceptionListener. 

For those who have been working with Java Swing, SWT, ..., the principle is similar to adding a listener to a graphical component.

The following code excerpt is rather straightforward, so, I guess you won't need any further explanation. By the way, I called the sleep(...) method on both threads to simulate a more realistic behavior for the TaskManager as well as the Task.



package main;

import java.beans.ExceptionListener;
import java.io.IOException;

public class TaskManager implements ExceptionListener{
   
    @Override
    public void exceptionThrown(Exception e) {
        System.out.println("An error occured in subtask --> TaskManager may need to take some action");
    }
   
   
    public static void main(String[] args) {
        TaskManager tm = new TaskManager();
        Task t = new Task(tm);
       
        Thread th = new Thread(t);
        th.start();
       
        int cpt = 0;
       
        // Main thread doing its own work
        while(cpt++ < 10){
            try {
                Thread.sleep(1000);
                System.out.println("Thread : " + Thread.currentThread().getName() + " - doing its job");
            } catch (InterruptedException e) {
                e.printStackTrace();
            }
        }
    }   
}

class Task implements Runnable{
    private ExceptionListener listener;
   
    public Task(ExceptionListener listener){
        this.listener = listener;
    }
   
    @Override
    public void run(){
        try{
            // ... simulating some processing done by the child Thread
            Thread.sleep(4000);
            throw new IOException("... the specified file does not exist (for instance)");
        }catch(IOException ioe){
            if(this.listener != null){
                // propagating the caught Exception to the ExceptionListener
                listener.exceptionThrown(ioe);
            }
        } catch (InterruptedException e) {
            e.printStackTrace();
        }
    }
   
}