Threads

Objectives

In this lab you will...

  • use the Thread class from the Java standard library
  • use Lock objects from the Java concurrency library
  • complete a multi-threaded program
  • learn some techniques for debugging multi-threaded programs using Eclipse

Pre-lab

Note: you must complete the pre-lab exercise at the end of this section and present it to your TA at the very beginning of your lab to receive full marks on this lab.

Most software applications you use are multi-threaded, meaning the program can be actively doing more than one function at a time. For example, when you print a document using your word processing software, you can continue working while the document is sent to the printer. As another example, in Eclipse, when you perform a search, you can choose to search in the background and continue working while the search is in progress.

A thread refers to a single sequential flow of control within the program. For instance, the flow of control related to printing in the word processor case,  is performed in a thread, as is the background search in Eclipse. Any Java program you have written contains at least one thread. You can read more about what a thread is at http://java.sun.com/docs/books/tutorial/essential/concurrency/index.html.

When a program has more than one thread running, the developer must be aware of and handle issues associated with concurrency.  For instance, when more than one thread is running and calling methods on the same object, two threads may be actively executing a method concurrently. In the first part of this lab, you'll get a taste of the kinds of problems that can arise from concurrency.

Pre-lab exercise: to be given to your TA at the start of your lab.
1) Download the application for the second part of this lab: threadslab-parttwo.zip.
2) How many threads are started when this application is run (excluding the main thread)?
3) As presented to you, does the code create a race condition? Briefly justify your answer.


In-lab Exercises

Part 1. Debugging a Simple Multithreaded Application

In this part of the lab, you will load an existing program into Eclipse and:

  • use the debugger to investigate the threads that are running, and
  • correct the synchronization in the program so that it runs correctly.

To get started:

  • Create the directory ~/cs211/labs/threads
  • in Eclipse, create a new Java project called ThreadsLab. Choose Create project from existing source and fill in the directory field with ~/cs211/labs/threads
  • create a new package in the ThreadsLab project called partone
  • download the code (threadslab-partone.zip)
  • import the code into the partone package by selecting the package, right-clicking and using Eclipse's Import wizard to import the zip file.

Your ThreadsLab project should now have a partone package with 3 classes (Counter, Accessor, Driver).

Try running the Driver as a Java application. Be patient - it may take upto a minute to run and produce output in the console. Do you get the result you expect? What if you run the application again? Do you get the same result each time you run the program?

Run the Driver using the debugger (i.e., right click on the Driver class and select "Debug as...Java application"). (You might want to set a break point before running the debugger.) Using the Debugger perspective in Eclipse, determine how many threads are running when the application executes.

Use Lock objects to fix the program to produce the expected (and correct) output. Which method(s) contain critical sections of code?

Part 2. Fixing a Cellular Phone Simulator

In this part of the lab, you will load an existing partially implemented program into Eclipse and complete its functionality.

To get started:

  • create a new package in your ThreadsLab project called cellular
  • download the code (threadslab-parttwo.zip)
  • import the code into the cellular package

This code provides a simple simulation of a cellular phone. The phone should accept onlyone call at a time. While a call is in progress, no other call should be accepted. Instead, the caller should receive an indication that the phone is not available (i.e., a busy signal).

The code you are given includes 3 classes:

  1. CellularPhone - a simulator of a phone (with no user interface). The phone can be told that a call has started, that a call has ended, and can display an informational string on its screen (i.e., the console in this case).
  2. PhoneCallGenerator - generates calls to a particular phone.
  3. Driver - a driver that calls the phone repeatedly.

When the program works correctly, the simulator should show the phone waiting, handling calls from Jenny and Sam and calls being dropped because of a busy signal. Note that the documentation provided with the startCall method of the CellularPhone class reflects the implementation provided to you. When the method works correctly, it will return true if the call is accepted and false if a call is already in progress (so the current call is dropped). A sample portion of output is shown below (note, the output will change each time the program is run because it is concurrent).

<Phone>: Waiting...
<Jenny>: Call (1) begins
    <Jenny>: Call (1) ends
<Jenny>: Call (2) begins

<Sam>: Busy, call (1) dropped
<Sam>: Busy, call (2) dropped

   <Jenny>: Call (2) ends
<Phone>: Waiting...
<Jenny>: Call (3) begins
   <Jenny>: Call (3) ends

The simulator attempts to handle 20 calls from each of Jenny and Sam before the program terminates.

The code that you have been given has synchronization problems. Make the program work correctly given the information about synchronization provided in lectures. Be sure to use Lock objects rather than synchronized methods. When you think you have the program working, show your solution to your TA.

Part 3. Enhancing the Cellular Phone Simulator

In this part of the lab, you will enhance the cellular phone simulator with the ability to handle text messages. The phone should be able to accept a message at any time. The phone should never miss accepting a message. When the phone is not busy handling a call, it should try to display all of the messages it has received. Once a message is printed, the phone can forget the message. The phone can remember only up to 10 messages at a time.

To help you implement this functionality, here is a class (MessageGenerator.java) that you can add to your package for generating text messages. You will need to create at least two MessageGenerators (just like PhoneCallGenerators) in the Driver class.

To use the MessageGenerator, you will need to add the following methods to the CellularPhone class:

  • public void addMessage( String newMessage )

You may also find it useful to define a helper method on CellularPhone:

  • private void displayMessages()

to print out all messages that have been received by the phone.

Finally, you will need to use some data structures to remember the messages received on the phone. A first-in first-out (FIFO) queue would work well for this purpose. Since you want to make sure to remember all messages received, you may want to check out:

When you have messages being generated and handled by your application, call your TA over and have them check it out!

In case the specification above is not clear, here is some sample output from our application that implements this functionality (we can receive messages from 4 message generators named father, mother, sister and brother. We even made messages from our mother be sent at higher priority!)

<Phone>: Waiting...
<Jenny>: Call (1) begins

<Sam>: Busy, call (1) dropped
    <Jenny>: Call (1) ends
<Phone>: Message: Mother 1
<Phone>: Message: Mother 2
<Phone>: Message: Mother 3
<Phone>: Message: Father 1
<Phone>: Message: Brother 1
<Phone>: Message: Sister 1
<Phone>: Message: Father 2
<Phone>: Message: Brother 2
<Phone>: Message: Father 3
<Phone>: Message: Brother 3
<Phone>: Message: Mother 4
<Phone>: Message: Sister 2
<Phone>: Message: Brother 4
<Phone>: Message: Mother 5
<Phone>: Message: Father 4
<Phone>: Message: Brother 5
<Phone>: Waiting...
<Jenny>: Call (2) begins
   <Jenny>: Call (2) ends
<Jenny>: Call (3) begins

<Sam>: Busy, call (2) dropped
<Sam>: Busy, call (3) dropped

   <Jenny>: Call (3) ends