Featured Whitepapers
Newsletter sign-up
View all newsletters

Sign up for our technology specific newsletters.

Enterprise Java
Email Address:

Can Assure save Java from the perils of multithreading?

Not without your help, but it's a big step in a good direction

  • Digg
  • Reddit
  • SlashDot
  • Stumble
  • del.icio.us
  • Technorati
  • dzone
The Java language contains one feature that is so dangerous, so difficult to avoid using, so hard to use correctly, and so pervasively used incorrectly that it has to rank as a serious design flaw. That feature is multithreading. Experienced programmers (myself included) are aware of the hazards associated with multithreading, and employ various strategies to ameliorate the problem. I've been dealing with various forms of multithreading since my first real job in the industry, which was sometime around 1973; and I consider myself a competent and careful programmer.

Therefore, I was shocked by what Assure showed me about some of my "thoroughly debugged" Java code. Assure is an easy to use runtime behavioral monitoring and analysis tool that was developed by Kuck & Associates Inc. (KAI). It found problems that were so glaringly obvious (once pointed out) that I would be embarrassed to outline them. It also found problems so subtle that I had to think a long time before I could even imagine how there could be such a problem.

This article will explore the tip of the iceberg, the very easiest part of the problem to see, by using Assure to debug example code provided by Sun with the JDK. Wouldn't you assume that such code was as close to bug-free as is humanly possible? This isn't the case, as we shall see. In the process of reading this article, perhaps you'll learn a little about writing code that is thread-safe to begin with, as I did in writing this article.

The extent of the multithreading problem in Java

Languages and environments other than Java permit the use of multiple threads. But Java applications are virtually impossible to write without using them, and most apps use a lot of them. Even the most trivial applet will have three threads: the applet's main run loop, the Java virtual machine's event loop, and the Java display manager's paint loop.

To this we can probably add even more threads for applications with animation timing loops, sound, and network communication. There can be no argument that Java's runtime environment is replete with threads, all running simultaneously and manipulating the same data. To deal with this chaos, Java provides just one low-level construct: the synchronized keyword.

The hazards of synchronization

Synchronization is both necessary and sufficient to control the execution of multithreaded code, but that's akin to saying a raft and an oar are enough to cross any body of water. Sure, you can do it. In practice, however, synchronization is very difficult to use correctly. Here's a list of some of the problems inherent with synchronization:

  • If you don't use synchronization enough, and in the right places, your program will execute using inconsistent sets of data, and thus will produce unpredictable results. This situation is called a data race, because multiple threads race each other to produce and/or consume their common data. This kind of problem typically manifests itself in your programs as random, nonreproducible bugs which, if you investigate the situation, appear to result from "impossible" configurations of your data, such as

    if(a==1) { b=2; }
    if((a==1)&&(b!=2)) { throw new Error("impossible error!"); }
    


  • If you use synchronization too much, or in the wrong places, your threads can deadlock, with two or more processes permanently blocked because they are waiting for each other to relinquish some resource they both want to use. This kind of problem typically results in the application "locking up."

  • Threads that temporarily have nothing to do must be suspended and resumed when there is something for them to do again. If a thread should be resumed, but no other thread issues the command, a permanently stalled thread can result.


Common strategies for dealing with multiple threads

Without turning this article into a tutorial on multithreaded programming, here are some good rules of thumb that are commonly used in Java programming. (For previous JavaWorld articles on multithreading, see Resources.)

  • Do all of your drawing in one place: either do all your drawing in the paint method, or do all your drawing in your run loop, and use the paint method only to set a "needs to be painted" flag. Conversely, do not do any drawing directly in response to various mouse, button, and network events.

  • Use semaphores to indicate when data is ready to be consumed by another thread.

  • Do as little as possible within synchronized methods. In particular, do not do anything that will not finish after some clearly foreseeable series of actions. Do not do anything inside synchronization that might block indefinitely, particularly I/O.

  • Use local variables rather than global variables.

  • Try to organize your code so each piece of data is manipulated in exactly one thread. Any data that is not shared between threads is guaranteed to be safe.

  • Synchronize code that you know will be used by multiple processes and that uses state that may be shared among the processes.


Assure: A tool that addresses synchronization problems

One day I was trying to solve a particularly hard-to-find display glitch, the kind that, to my eye, simply reeked of a synchronization problem. As I frequently do when temporarily stumped, I consulted my peers on Usenet, using Deja News (see Resources), and found a brief reference to Assure. Assure is a runtime analysis tool that examines your program's behavior in two phases:

  • In the first phase, you run your Java application (or applet) using Assure's specialized version of the Java virtual machine, which produces a log file.

  • In the second phase, you run the Assure tool itself to analyze the log and present the results. Assure looks for dynamic situations where data races, deadlocks, and thread stalls might occur. The algorithms Assure uses to analyze the target program's behavior are not foolproof -- they indicate the possibility, not the certainty, that a problem exists; and they're not guaranteed to detect all problems that do exist.


Debugging threads using Assure

For the purposes of this article, I decided to use one of Sun's own examples as a guinea pig; both because these examples are supposed to be good examples, and because they're readily available, simple, clean little programs. I didn't have to look very hard; the Molecule Viewer demo was the second one I looked at using Assure.

The Molecule Viewer is a fairly simple applet that allows you to view a molecular model from various angles, using the mouse to control the point of view. This demo is found in demo/MoleculeViewer/ below your JDK 1.1 directory.

The first step is to run the demo using Assure's Java runtime, instead of the regular Sun JDK (or your browser's Java, or whatever other Java engine you would normally use):

cd \java\jdk-1.1\demo\MoleculeViewer
d:\java\assurej11\bin\appletviewer -J-assurej example1.html


The model pops up. Drag it around a little using the mouse, then hit Exit. Now run Assure on the log file that has been created. Because I didn't specify a name, the file is called assurej.kgi.

  • Digg
  • Reddit
  • SlashDot
  • Stumble
  • del.icio.us
  • Technorati
  • dzone
Comment
Login
Forgot your account info?
Add comment
Anonymous comments subject to approval. Register here for member benefits.
Have a JavaWorld account? Log in here. Register now for a free account.
Resources
  • Read what developer Kuck & Associates Inc. (KAI) has to say about Assure and download a free, time-limited but fully functional trial version of the product http://www.kai.com/assurej/
  • Get the basic scoop on threads and synchronization, in Chapter 17 of the Java Language Specification http://java.sun.com/docs/books/jls/html/17.doc.html#30206
  • A good paper about higher-level solutions to thread synchronization problems http://www.cs.hope.edu/~dershem/reu/papers97/jipteam/Final.html
  • Download several useful higher-level synchronization classes http://gee.cs.oswego.edu/dl/classes/EDU/oswego/cs/dl/util/concurrent/intro.html
  • See Chuck McManis's Java In Depth column in JavaWorld http://www.javaworld.com/javaworld/jw-03-1998/jw-03-indepth.html
  • The Usenet resource Deja News is at http://www.dejanews.com