46.

Orphaned Threads and GUIs

In the context of GUI programming, it is quite easy to introduce orphaned threads. Often, GUI programs will spawn threads in response to various events, each time locking the application until the spawned thread returns. But if the spawned thread throws an unchecked exception, you've got an orphaned thread.

In our first attempt to integrate support for JUnit into DrJava, we added a Test button to the toolbar. When pressed on a valid subclass of junit.framework.TestCase, this button would spawn a separate thread to invoke JUnit on the corresponding class file.

As with the interactions pane, DrJava would not require the user to explicitly put a class on the system classpath before trying to test it. Instead, DrJava would check the package name of the test class and automatically add the implied root directory of the source packages to the class path passed to JUnit. Provided that the classfiles were kept in the same directories as the corresponding source files (as is done by default in DrJava), this would work fine.

Also, if the user modified the file, DrJava would prompt him to save and compile before calling JUnit. But if the user had compiled the classfile for a test class to a package directory hierarchy distinct from that of the source file, the directory hierarchy for the classfile would not be on his system classpath. If the user opened the corresponding source file and immediately called Test on it, JUnit would be unable to locate the corresponding class file. It would throw a ClassNotFoundException.

But this scenario was overlooked, which meant that we didn't code in logic to handle these ClassNotFoundExceptions. So they propagated to the top level of the spawned thread, resulting in its termination.

Meanwhile, the application would lock until the spawned thread returned a report of the result of running JUnit on the test class—which, of course, would never happen. The result? Every user's worst nightmare: a frozen application.

Once this problem was identified, the solution was easy: catch the ClassNotFoundException thrown from JUnit and generate an appropriate report of the result. Of course, a new unit test was put into place to make sure that this particular bug never occurred again.

Unit Tests and Multithreading

Because DrJava makes heavy use of multithreading, we have encountered Orphaned Threads, along with other multithreading bugs, on many occasions. But, luckily, few of these bugs make it past our unit tests. One main reason that the unit tests save us so often from multithreading problems is that the tests interact with the application much more quickly than any human user could. This ultrafast interaction tends to cause all of the program threads to interact in unexpected ways, revealing bugs that a user wouldn't normally encounter. (Of course, on the rare occasion that a user did happen to trip up on such a bug, it would be extraordinarily difficult to diagnose, or even repeat.) For this reason, a strong suite of unit tests over multithreaded code is essential, even more so than in other contexts.

(For more on the DrJava project, see Resources, "Chapter 12.)

As the earlier examples demonstrate, Orphaned Threads can have devastating symptoms. And in the context of a multithreaded application, they aren't hard to generate.

Tip 

Use the sharp knife of multithreading with caution. Although it can deliver a more efficient and understandable program, it is an easy way to break an invariant expected to hold in one thread.



Bug Patterns in Java
Bug Patterns In Java
ISBN: 1590590619
EAN: 2147483647
Year: N/A
Pages: 95
Authors: Eric Allen

flylib.com © 2008-2017.
If you may any questions please contact us: flylib@qtcs.net