Bruce Eckel's Thinking in Java Contents | Prev | Next

Summary

It is vital to learn when to use multithreading and when to avoid it. The main reason to use it is to manage a number of tasks whose intermingling will make more efficient use of the computer or be more convenient for the user. The classic example of resource balancing is using the CPU during I/O waits. The classic example of user convenience is monitoring a “stop” button during long downloads.

The main drawbacks to multithreading are:

  1. Slowdown while waiting for shared resources
  2. Additional CPU overhead required to manage threads
  3. Unrewarded complexity, such as the silly idea of having a separate thread to update each element of an array
  4. Pathologies including starving, racing, and deadlock
An additional advantage to threads is that they substitute “light” execution context switches (of the order of 100 instructions) for “heavy” process context switches (of the order of 1000s of instructions). Since all threads in a given process share the same memory space, a light context switch changes only program execution and local variables. On the other hand, a process change, the heavy context switch, must exchange the full memory space.

Threading is like stepping into an entirely new world and learning a whole new programming language, or at least a new set of language concepts. With the appearance of thread support in most microcomputer operating systems, extensions for threads have also been appearing in programming languages or libraries. In all cases, thread programming (1) seems mysterious and requires a shift in the way you think about programming and (2) looks similar to thread support in other languages, so when you understand threads, you understand a common tongue. And although support for threads can make Java seem like a more complicated language, don’t blame Java. Threads are tricky.

One of the biggest difficulties with threads occurs because more than one thread might be sharing a resource, such as the memory in an object, and you must make sure that multiple threads don’t try to read and change that resource at the same time. This requires judicious use of the synchronized keyword, which is a helpful tool but must be understood thoroughly because it can quietly introduce deadlock situations.

In addition, there’s a certain art to the application of threads. Java is designed to allow you to create as many objects as you need to solve your problem – at least in theory. (Creating millions of objects for an engineering finite-element analysis, for example, might not be practical in Java.) However, it seems that there is an upper bound to the number of threads you’ll want to create because at some point a large number of threads seems to become unwieldy. This critical point is not in the many thousands as it might be with objects, but rather in the neighborhood of less than 100. As you often create only a handful of threads to solve a problem, this is typically not much of a limit, yet in a more general design it becomes a constraint.

A significant non-intuitive issue in threading is that, because of thread scheduling, you can typically make your applications run faster by inserting calls to sleep( ) inside run( )’s main loop. This definitely makes it feel like an art, in particular when the longer delays seem to speed up performance. Of course, the reason this happens is that shorter delays can cause the end-of- sleep( ) scheduler interrupt to happen before the running thread is ready to go to sleep, forcing the scheduler to stop it and restart it later so it can finish what it was doing and then go to sleep. It takes extra thought to realize how messy things can get.

One thing you might notice missing in this chapter is an animation example, which is one of the most popular things to do with applets. However, a complete solution (with sound) to this problem comes with the Java JDK (available at java.sun.com) in the demo section. In addition, we can expect better animation support to become part of future versions of Java, while completely different non-Java, non-programming solutions to animation for the Web are appearing that will probably be superior to traditional approaches. For explanations about how Java animation works, see Core Java by Cornell & Horstmann, Prentice-Hall 1997. For more advanced discussions of threading, see Concurrent Programming in Java by Doug Lea, Addison-Wesley 1997, or Java Threads by Oaks & Wong, O’Reilly 1997.

Contents | Prev | Next