Friday, January 9, 2009

On Never Using System.exit()

In one of the code reviews, I got a feedback to not use System.exit() function call at all. This was a little surprising for me but the explanation for that rule was very simple and made total sense. It's because there may be some worker thread is doing some important job (like committing a database transaction) and System.exit() will abruptly kill those threads leading to nasty bugs as you already might know.

The scenario is roughly as follows:

// A program that uses System.exit().

// MainUsingSystemExit.java
import java.io.BufferedReader;
import java.io.IOException;
import java.io.InputStreamReader;

public class MainUsingSystemExit {
  public static void main(String[] args)
      throws IOException { // You should never do this, I'm doing here for the
                           // sake of brevity of the example in the blog.
    DatabaseThread dbThread = new DatabaseThread();
    dbThread.start();

    BufferedReader reader
        = new BufferedReader(new InputStreamReader(System.in));
    while (true) {
      // TIP: In the code below, the letter 'N' is uppercase, you know why? It's
      // because that's the default answer if you don't enter anything. This is
      // a very common convention in CLI apps.
      System.out.print("Do you want to terminate? [y/N]: ");
      String userInput = reader.readLine();

      if ("y".equalsIgnoreCase(userInput)) {
        // The problem with the System.exit() below is simple, the
        // DatabaseThread is killed and that's very bad as you know.
        System.exit(0);
      }
    }
  }
}

// DatabaseThread.java
public class DatabaseThread extends Thread {
  public void run() {
    // Some db related operation.
    while (true) {
      try {
        Thread.sleep(5000);
      } catch (InterruptedException e) {}

      System.out.println("Database thread is still alive.");
    }
  }
}

So, how do we deal with such a code, in a clean way from the design point of view too? Solution: Observer pattern to the rescue!

We'll create a listener interface called ShutdownListener which will have a single method called shutdown() which is invoked when the system is about to go down. Those who'd like to clean-up stuff before shutdown can implement the interface and do their clean-up in the shutdown() method.

// A program that DOES NOT use System.exit().
public interface ShutdownListener {
  // Called when it's time to shutdown.
  public void shutdown();
}

And the DatabaseThread is one such class that should implement the ShutdownListener interface.

// DatabaseThread.java (modified)
public class DatabaseThread
    extends Thread
    implements ShutdownListener {
  private boolean shutdown;

  public void run() {
    // Some db related operation.
    while (!shutdown) {
      try {
        Thread.sleep(5000);
      } catch (InterruptedException e) {}

      System.out.println("Database thread is still alive.");
    }

    System.out.println("Database thread going down.");
  }

  public void shutdown() {
    shutdown = true;
    this.interrupt();
  }
}

The synchronization issues aren't handled here to not clutter the code in the blog but should be taken care.

We'll have a ShutdownHandler class where all the listeners will be registered. It can also register a shutdown hook* which does nothing but calls its own initiateShutdown() method which goes and calls the shutdown() method of all the registered ShutdownListeners.

import java.util.ArrayList;
import java.util.Iterator;
import java.util.List;

public class ShutdownHandler {
  private List shutdownListeners;

  public ShutdownHandler() {
    shutdownListeners = new ArrayList();

    // For handling TERM, INT signals.
    Runtime.getRuntime().addShutdownHook(new Thread() {
      public void run() {
        ShutdownHandler.this.initiateShutdown();
      }
    });
  }

  public void registerShutdownListener(ShutdownListener listener) {
    shutdownListeners.add(listener);
  }

  public void initiateShutdown() {
    Iterator iterator = shutdownListeners.iterator();

    while (iterator.hasNext()) {
      ShutdownListener listener = (ShutdownListener) iterator.next();
      listener.shutdown();
    }
  }
}

And finally, the new main():

import java.io.BufferedReader;
import java.io.IOException;
import java.io.InputStreamReader;

public class MainWithoutSystemExit {
  public static void main(String[] args) throws IOException {
    DatabaseThread dbThread = new DatabaseThread();
    dbThread.start();

    ShutdownHandler shutdownHandler = new ShutdownHandler();
    shutdownHandler.registerShutdownListener(dbThread);

    BufferedReader reader
        = new BufferedReader(new InputStreamReader(System.in));
    while (true) {
      System.out.print("Do you want to terminate? [y/N]: ");
      String userInput = reader.readLine();

      if ("y".equalsIgnoreCase(userInput)) {
        // Calling the ShutdownHandler's shutdown() method
        // instead of System.exit()
        shutdownHandler.initiateShutdown();
        return;
      }
    }
  }
}

As you can see, the ShutdownHandler's initiateShutdown() is called instead of System.exit() in the new main() method. Now if we've a new SocketThread or some other thread that needs a graceful exit, all we've to do is implement ShutdownListener and register it with the ShutdownHandler.

Now, go look in your code and see how you can eliminate System.exit() calls altogether. See if that brings out a better design. Or do you think this idea of not using System.exit() is just crazy?

* Thanks to Ajeya for reminding me about shutdown hooks.

Make Sure to Return the Right Exit Codes

Every process that finished its execution can return an integer value back to the parent process indicating its result. Often an exit code of '0' means the child process was executed successfully and a value greater than '0' indicates failure.

On a *NIX machine, the variable '$?' has the exit code returned by the last executed process. For example:

srikanth@workstation - [~]
$ find . -nam "*.c"              # Intentionally trying a wrong option
find: invalid predicate `-nam'

srikanth@workstation - [~]
$ echo $?
1                                # >0, process failed

srikanth@workstation - [~]
$ find . -name "*.c"
./test.c

srikanth@workstation - [~]
$ echo $?
0                                # Process execution successful

srikanth@workstation - [~]
$

But too often I've seen programmers not taking care of the exit codes for the applications or some small-time utility programs they write. I've done it myself when I started out programming partly because I didn't know the significance of the exit codes. But they are very helpful.

Sometimes you've to spawn a new process from your program to accomplish something 'cause you don't have an API exposed for it in your language. At these times, the exit code returned by the child process can be extremely useful.

So, when writing some new command line utility or an application, remember to:
  • Always return an exit code: 0 for success; 1 <= exit_code <= 255 for failure
  • Don't return negative exit codes: I've seen this in some code; I didn't know it was invalid till someone had an issue with it. At least on UNIX, the valid exit codes are from 0 to 255
  • Document the exit codes: Like 1 for database failure, 2 for mis-configuration, etc.
That's it, happy coding!

Friday, January 2, 2009

My Simple New Year Resolutions for 2009

I never took new year resolutions but in the previous year at some point I decided to create a list of things I wanted to learn and published it in my blog. It worked very well, I received a lot of invaluable comments, I kept coming back to the same post to keep myself on track. It really helps, you should write one too.

So this year I decided to broaden the scope of my resolutions from just technology to my life as a whole. These are my simple resolutions:

Do As Less As Possible

Sometimes I feel like doing everything, I mean at once. Like learning C++, completing a networking-related certification, mastering Python, doing an Open Source project, going for gym, learning Emacs, participating in Mumbai marathon, photography and watching falling stars.

And the problem I have is, when I'm doing something I would want to do something else. So this year, I decided to do only 3 things:
  • C++
  • Algorithms and Data Structures
  • Gymming
The picky professor in you may say that "Algorithms and Data Structures" are 2 things, but... it's okay, they're a bit related.


Take It Easy

There's something in me that's absolutely restless (I guess that's there in everyone). It constantly screams at you to do something great and significant in life but it doesn't have the patience to wait for you to complete. It wants us to do many things. From now on, I'll refuse to listen to that voice. I've heard it enough, now I want to concentrate on doing it.

It's OK to fail sometimes. It's OK to not achieve some of your goals. It's absolutely fine to do nothing productive on weekends. It's perfectly cool to watch a crappy Hindi movie with coworkers. It's nice to chill out and feel good. It's in fact re-energizing. It's nice to visit places. It's good to pass time chit-chatting with friends on weekends. All work and no play will only make Srikanth a dull boy. But dull no more :)


Be Mr.Fit

I wanted to run like Matt Damon in The Bourne Supremacy today morning. I don't know why. Just wanted to run like there's no ending. That's when I realized I didn't run since I left college. I didn't play any outdoor games too. It's time to do all that, again. And it's also the time to hit the gym to keep me fit.

My friend Ranganathan told me a few inspiring words when I met him recently, it was roughly: "When you lose everything in life, such as money and power, and if you're still alive, the only thing remaining is your body."

So, what are your new year resolutions?