This article may contain URLs that were valid when originally published, but now link to sites or pages that no longer exist. To maintain the flow of the article, we've left these URLs in the text, but disabled the links.


MIND


java911@microsoft.com         Download the code (7KB)
Jonathan Locke

The War of the Condiments

How can I get a stack trace for my Java program as a String?

As you've probably noticed, printing out a stack trace in Java is quite simple—the static method Thread.dumpStack prints out a stack trace for the calling thread by creating a new Exception, and then printing the stack trace information held by the Exception like this:


 public static void dumpStack() 
 {
     new Exception("Stack trace").printStackTrace();
 }
      You may have missed the overload of Throwable.printStackTrace (Throwable is the base class for Exception) that lets you print a stack trace to a java.io.PrintStream or java.io.PrintWriter. I'll use the PrintWriter overload since PrintWriters are the more modern of the two classes. (Character-based output streams were added in JDK 1.1.) A PrintWriter is a subclass of java.io.Writer, and a Writer is simply a Unicode, character-based (as opposed to byte-based) output stream.
      Looking at PrintWriter.java, you can see that PrintWriters may be constructed with any raw Writer as an argument. The particular Writer I will use here is an instance of java.io.CharArrayWriter. A C=rArrayWriter provides the functionality of a Writer, but rather than writing characters to a persistent storage device like a hard disk, it is written into a Java char array in memory. Once the printStackTrace method finishes filling in the CharArrayWriter and returns, I then call the CharArrayWriter's toString method and return the stack dump String (see Figure 1.)


Java Tip of the Month

As you may know, Java Class objects for Java classes can be found by name using the Class.forName method, like this:


Class c = Class.forName("java.lang.String");
c.newInstance();
But did you know about the new class literals feature introduced in JDK 1.1? You can write the same code like this:

 Class c = java.lang.String.class;
 c.newInstance();

How can I traverse a directory tree in Java?
The java.io.File class has methods for dealing with directories as well as files. The list method returns a String array of files and directories held in the directory represented by the File object. If the File object does not happen to be a directory, list will return null.
      The code in Figure 2 walks a directory tree given a root directory, a WalkObserver interface (a callback interface used to report each file encountered), and an indentLevel, which is increased at each level of recursion. For each file in the rootDirectory's file list, a new File object is constructed. After calling the observer with the file, a check is made to see if the file itself is a directory. If it is, a walk of that subtree is made by recursing and passing in the new file as the new rootDirectory. A WalkTest program that walks the directory tree passed in via the command line is included with the online code (listed at the top of this page).

Is it possible to call one constructor from another? I tried something like this, but it didn't work:

 class A
 {
     public A()
     {
         // do whatever
     }
 
     public A(String s)
     {
         this.A();
         // do whatever
     }
 }

Yes, you can do what you are trying to do. You just have the wrong syntax. The code above doesn't compile because you are trying to invoke A as a method rather than as a constructor. The compiler error for the previous code will be something like "Method A() not found in class A." You need to use a different syntax to invoke the constructor A. The syntax to call constructor A is simply this(), and must be the first statement in the overloaded constructor. Likewise, if you wanted to chain a new constructor that called the A(String s) constructor, you would write this(s).

What is a finalizer and why would I want to use one?
A finalizer is a special method that is called when an object is ready to be discarded. The garbage collector has determined that the object is unreachable, but it has not yet been freed. The prototype for finalizer methods can be found in the java.lang.Object. It looks like this:

 protected void finalize() throws Throwable { }
      The purpose of this special method is to allow objects that are holding references to native resources to free them before being garbage collected. Pure Java classes (for example, classes that don't involve native code) generally don't need finalizers; the VM's garbage collector is sufficient to automatically clean up after them because they only consume resources from the Java garbage-collected heap. This makes finalizers very different from (and much rarer than) C++ destructors, which manually take on a lot of the work that a garbage collector would otherwise perform.
      An example of a nonpure Java class that does have a finalizer method is the java.awt.Graphics class. The Graphics.finalize method calls Graphics.dispose, which is ultimately implemented in native code. The native dispose method frees any C-allocated data structures and/or operating system resources associated with the Graphics object.
      There are a few gotchas to be aware of with finalizers. For one thing, finalizers don't chain the way constructors do. So you should get in the habit of manually making every finalizer call its superclass's finalize method, like so:

 public void finalize()
 {
     super.finalize();
 
     // do whatever...
 }
This will ensure that any finalization code in the superclass, or further up the inheritance chain, will be run.
      A couple of more subtle gotchas are that the order of object finalization and the thread that does the job are both undefined. This may not sound like a big deal since the object is unreachable, but just sprinkle a few synchronized keywords around and have your finalizer do something significant—you may wind up singing a different tune!
       Figure 3 demonstrates finalization. A new FinalizeMe object is created and assigned to the stack variable f. The garbage collector and finalization process are invoked through System.gc and System.runFinalization to demonstrate that f's finalizer is not run (because the f stack variable still references it). Next, I remove the only reference to the object by setting f to null. Then, I run the garbage collector and finalization process again. This time the finalizer is called. The output from running FinalizeMe looks like this:

 J:\mind\911>java FinalizeMe
 First gc
 Second gc
 In finalizer!
 Done.

Java Resource of the Month

The Stedelijk Museum of Modern Art in Amsterdam has Java search and timeline applets on their hyper-modern Web site that help you locate artists and art works. A URL well worth the visit: http://www.stedelijk.nl/eng/index.html


I've heard the word deadlock mentioned in a variety of places, including past Java 911 columns, but I'm not a hundred percent sure what it means. Can you show me an example of a deadlock? Also, what is a race condition?

Why, soitainly! Figure 4 implements a classic deadlock example. In this example, two people are sitting at a table with a salt and pepper shaker. One person picks up the salt and the other picks up the pepper. The first person then says "If you'll first give me the salt, then I'll give you the pepper." And the second person says "If you first give me the pepper, then I'll give you the salt." Since neither party is willing to suspend their requirements until they have acquired the other's resource, a deadlock is reached and nothing further can be accomplished.
      In Figure 4 , each person is represented by a thread, and the salt and pepper shakers are represented by object instances (don't forget that all objects can potentially have Java synchronization monitors associated with them). The main thread of execution is a referee thread, which initializes the wantsPepper and wantsSalt threads, and waits for both to obtain locks on their objects. After each thread starts up and acquires its object, it waits for the referee to perform a notifyAll on the go object.
      Once the referee says go, each thread tries to take the opposing thread's object while still holding onto the lock for its own object (if you give me the pepper, then I'll give you the salt and vice versa). This results in a deadlock because neither thread can acquire the lock that the opposite thread still holds. Stepping through this code in a multithreaded Java debugger like Visual J++® can be quite enlightening.
      You would get a race condition if you took the referee out of Figure 4 . There are two possible outcomes depending on thread scheduling. The first outcome is that one thread manages to acquire and release both locks before the other thread has a chance to get its first lock. In this case, the code doesn't deadlock at all and both threads get what they want. The other outcome is that thread scheduling is even enough so that each thread acquires one lock. In this case, the code does deadlock. As you can see, race conditions are intermittent by nature because they depend on the relative speed of execution of two or more threads (thus the name race condition). This can make them especially hard to debug. At least with deadlocks, you can hit Ctrl+Break and look at which threads are holding which monitor locks.


From the April 1998 issue of Microsoft Interactive Developer.