Java tips

Here are a few explanations of java issues that I found worth saving.

Examine tracebacks without stopping Java

You can dump out tracebacks of a Java process at any time, and see what line of code is being executed by each thread. This is VERY handy for analysing thread problems, like deadlock.

At the NT-DOS prompt, just type control-break (a little used key on the upper-right).

On Unix, send a QUIT signal to the java process group. Here's how to send a QUIT signal:

  % kill -QUIT -32352 
where 32352 is the process group ID (PGID). You must include the minus sign before the PGID. Get the PGID with this command:
  % ps -e -o 'pgid user fname args' | grep java |sort -n
The first column will contain the PGID. The QUIT signal is often bound to control-\ (backslash).

I map the QUIT signal to control-A with

  % stty quit "^A"

You'll get the tracebacks printed to the screen, without causing the program to exit. This dump is more thorough than you get from an uncaught exception. Read more at http://developer.java.sun.com/developer/onlineTraining/Programming/JDCBook/stack.html

To see uncompiled line numbers, use the option "java -Djava.compiler=NONE com.lgc.stuff" when you launch the process in question.

I have not found a way to send a signal under Cygnus bash on Windows.

Do not ignore Interrupted Exceptions

If you catch an InterruptedException, then you should stop what you are doing, rethrow the InterruptedException, or call Thread.currentThread().interrupt();

Time-consuming code should check Thread.interrupted() regularly. If true, then respond just as if you had caught an InterruptedException.

Do NOT cause an interrupt to be ignored, or no one will be able to stop your Thread.

You will only get an InterruptedException if someone has deliberately called Thread.interrupt(). They want your Thread to clean up and return from the Thread.run() method.

If your utility method is not in a position to clean up, then it should rethrow the InterruptedException. Do not convert and rethrow a different kind of Exception.

If this is too difficult, then at least call Thread.currentThread().interrupt() so that later code can handle the interrupt correctly.

 
public void foo() {
  try {Thread.sleep(1000);}
  catch (InterruptedException e) {
    Thread.currentThread().interrupt();
  }
}

There is no other safe way to stop a Thread because Thread.stop() is deprecated.

Running and interrupting threads after a time limit

Here is a way to start a series of Threads and interrupt them if not completed after a time limit:
  /** Run many Threads and interrupt if not finished after a time limit.
      @param thread Start these threads and interrupt if necessary.
      @param millisWait Milliseconds to wait for threads to complete.
      If zero, wait forever.
      @param millisPause Wait this many milliseconds between starting
      each thread, to avoid clobbering resources.
      @return Array of booleans for each thread.
      Element is true if thread was interrupted because of timeout or
      because this thread was interrupted.
  */
  public static boolean[] run(Thread[] thread, long millisWait,
                              long millisPause) {
    long end = System.currentTimeMillis() + millisWait;
    if (millisWait == 0) {
      end = Long.MAX_VALUE;
    }
    boolean interruptedMe = false;
    for (int i=0; i<thread.length; ++i) {
      if (thread[i] != null)
        thread[i].start();
      if (millisPause >0) {
        try {
          Thread.sleep(millisPause);
        } catch (InterruptedException e) {
          interruptedMe = true;
        }
      }
    }
    boolean allFinished = false;
    while (!interruptedMe &&
           System.currentTimeMillis() < end &&
           !allFinished) {
      allFinished = true;
      for (int i=0; allFinished && i<thread.length; ++i) {
        if (thread[i] != null && thread[i].isAlive())
          allFinished = false;
      }
      if (!allFinished) {
          try {
            Thread.sleep(200);
          } catch (InterruptedException e) {
            interruptedMe = true;
          }
      }
    }
    boolean[] interrupted = new boolean[thread.length];
    for (int i=0; i<thread.length; ++i) {
      if (thread[i] != null && thread[i].isAlive()) {
        thread[i].interrupt();
        interrupted[i] = true;
      } else {
        interrupted[i] = false;
      }
    }
    if (interruptedMe) {
      Thread.currentThread().interrupt();
    }
    return interrupted;
  }

Getting a list of running Threads

Here is a way to get a list of Threads that are still alive
  public static String[] getThreadNames() {
    ThreadGroup group = Thread.currentThread().getThreadGroup();
    ThreadGroup parent = null;
    while ( (parent = group.getParent()) != null ) {
      group = parent;
    }
    Thread[] threads = new Thread[group.activeCount()];
    group.enumerate(threads);
    java.util.HashSet set = new java.util.HashSet();
    for (int i=0; i < threads.length; ++i) {
      if (threads[i] != null && threads[i].isAlive()) {
        try {
          set.add(threads[i].getThreadGroup().getName()+","
                  +threads[i].getName()+","
                  +threads[i].getPriority());
        } catch (Throwable e) {e.printStackTrace();}
      }
    }
    String[] result = (String[]) set.toArray(new String[0]);
    java.util.Arrays.sort(result);
    return result;
  }

Quick profiling

Try the built-in hprof profiler, with the GNU PerfAnal. See a fuller explanation at
http://developer.java.sun.com/developer/technicalArticles/Programming/perfanal/

If you start a java process from the command line, add the following flag to create a logfile called temp.hprof :

java -Xrunhprof:cpu=samples,depth=30,file=temp.hprof com.acme.YourClassMain
Look at the file graphically with
java -jar PerfAnal.jar temp.hprof

Localize your java Logger

Internationalize your java log messages almost for free.

Here's an example Foo.java:

  import java.util.logging.Logger;

  public class Foo {
    private static final Logger LOG 
      = Logger.getLogger(Foo.class.getName(),
                         Foo.class.getName());

    public static void main(String[] a) {
       LOG.info("Everything is dandy."); // old way
       LOG.info("dandy");                // new way
    }
  }
Create a Foo.properties file with this line
   dandy=Everything is dandy.
in the same directory as Foo.class.

You'll see the same message twice.

Or create Foo_hick.properties with

   dandy=Boy howdy.
and run
   java -Duser.language=hick test.Foo
(Real languages use two-letter codes like en, es, ch, fr.)

Exception Handling

I often see code where an Exception is caught only to print some general error message and return. That isn't really handling an Exception. The original Exception is being lost, along with the stack trace, and any detailed getMessage(). Nothing has been done to fix the problem so that work can continue.

If the Exception reaches the main(), then it is reasonable to print out error information and return. (Do not call System.exit.)

Best, just pass or rethrow the Exception out of main(). Then the user can see the entire stack trace. It is reasonable for a main() that manipulates files to declare "throws IOException."

Feel free to print out as much debug information as you can before rethrowing an Exception. But don't throw away that Exception unless you've fixed the problem and normal work can continue.

If you feel like converting one type of Exception into another, then use initCause(), so that the original Exception and its stacktrace are not lost:

try {
  foo();
} catch (TheirException te) {
  MyException me = new MyException("My bad.");
  me.initCause(te);
  throw me;
}

Bad redrawing performance on Windows

Occasionally, I have run across really bad redrawing performance on Windows. Try this -Dswing.volatileImageBufferEnabled=false or -Dsun.java2d.noddraw=true or -Dsun.java2d.ddoffscreen=false . For more information, see http://bugs.sun.com/bugdatabase/view_bug.do?bug_id=4527745  
Bill Harlan, 2000
Return to parent directory.
Revision: $Id: javatips.html,v 1.9 2005/01/17 22:43:45 harlan Exp $