Follow Techotopia on Twitter

On-line Guides
All Guides
eBook Store
iOS / Android
Linux for Beginners
Office Productivity
Linux Installation
Linux Security
Linux Utilities
Linux Virtualization
Linux Kernel
System/Network Admin
Scripting Languages
Development Tools
Web Development
GUI Toolkits/Desktop
Mail Systems
Eclipse Documentation

How To Guides
General System Admin
Linux Security
Linux Filesystems
Web Servers
Graphics & Desktop
PC Hardware
Problem Solutions




Thinking in Java
Prev Contents / Index Next


Solutions to selected exercises can be found in the electronic document The Thinking in Java Annotated Solution Guide, available for a small fee from

  1. Inherit a class from Thread and override the run( ) method. Inside run( ), print a message, and then call sleep( ). Repeat this three times, then return from run( ). Put a start-up message in the constructor and override finalize( ) to print a shut-down message. Make a separate thread class that calls System.gc( ) and System.runFinalization( ) inside run( ), printing a message as it does so. Make several thread objects of both types and run them to see what happens. Experiment with different sleep times in to see what happens.
  2. In Chapter 8, locate the example, which consists of four files. In, the class Event is based on watching the time. Change Event so that it is a Thread, and change the rest of the design so that it works with this new Thread-based Event.
  3. Modify the previous exercise so that the java.util.Timer class is used to run the system.
  4. Modify so that all the threads are daemon threads and verify that the program ends as soon as main( ) is able to exit.
  5. Demonstrate that java.util.Timer scales to large numbers by creating a program that generates many Timer objects that perform some simple task when the timeout completes (if you want to get fancy, you can jump forward to the “Windows and Applets” chapter and use the Timer objects to draw pixels on the screen, but printing to the console is sufficient).
  6. Demonstrate that a synchronized method in a class can call a second synchronized method in the same class, which can then call a third synchronized method in the same class. Create a separate Thread object that invokes the first synchronized method.
  7. Create two Thread subclasses, one with a run( ) that starts up and then calls wait( ). The other class’s run( ) should capture the reference of the first Thread object. Its run( ) should call notifyAll( ) for the first thread after some number of seconds have passed so that first thread can print a message.
  8. Create an example of a “busy wait.” One thread sleeps for awhile and then sets a flag to true. The second thread watches that flag inside a while loop (this is the “busy wait”) and when the flag becomes true, sets it back to false and reports the change to the console. Note how much wasted time the program spends inside the “busy wait” and create a second version of the program that uses wait( ) instead of the “busy wait.”
  9. Modify to use notifyAll( ) and observe any difference in behavior.
  10. Modify so that there are multiple WaitPersons, and indicate which one gets each Order.
  11. Modify so that multiple WaitPersons generate order requests to multiple Chefs, who produce orders and notify the WaitPerson who generated the request. You’ll need to use queues for both incoming order requests and outgoing orders.
  12. Modify the previous exercise to add Customer objects that are also threads. The Customers will place order requests with WaitPersons, who give the requests to the Chefs, who fulfill the orders and notify the appropriate WaitPerson, who gives it to the appropriate Customer.
  13. Modify so that Sender reads and sends lines from a text file.
  14. Change so that the philosophers just pick the next available chopstick (when a philosopher is done with their chopsticks, they drop them into a bin. When a philosopher wants to eat, they take the next two available chopsticks from the bin). Does this eliminate the possibility of deadlock? Can you re-introduce deadlock by simply reducing the number of available chopsticks?
  15. Inherit a class from java.util.Timer and implement the requestStop( ) method as in
  16. Modify so that all threads receive an interrupt( ) before they are completed.
  17. Solve a single producer, single consumer problem using wait( ) and notify( ). The producer must not overflow the receiver's buffer, which can happen if the producer is faster than the consumer. If the consumer is faster than the producer, then it must not read the same data more than once. Do not assume anything about the relative speeds of the producer or consumer.

[68] Runnable was in Java 1.0, while inner classes were not introduced until Java 1.1, which may partially account for the existence of Runnable. Also, traditional multithreading architectures focused on a function to be run rather than an object. My preference is always to inherit from Thread if I can; it seems cleaner and more flexible to me.

[69] Some examples were developed on a dual-processor Win2K machine that would immediately show collisions. However, the same example run on single-processor machines might run for extended periods without demonstrating a collision—this is the kind of scary behavior that makes multithreading difficult. You can imagine developing on a single-processor machine and thinking that your code is thread safe, then discovering breakages as soon as it’s moved to a multiprocessor machine.

[70] Inspired by Joshua Bloch’s Effective Java, Addison-Wesley 2001, page 190.

[71] See Design Patterns, by Gamma et. al., Addison-Wesley 1995.

[72] Effective Java, by Joshua Bloch, Addison-Wesley 2001, page 211.

[73] And in a number of other places throughout the experience of Java. Well, why stop there?—I’ve consulted on more than a few projects where this has applied.

Thinking in Java
Prev Contents / Index Next

   Reproduced courtesy of Bruce Eckel, MindView, Inc. Design by Interspire