Exercises

Included below are short-answer and programming exercises. Answers are provided for those exercises whose exercise number is a hyperlink. Because college faculty use these exercises in their exams, we have provided answers to roughly half of the exercises included here.


15.3 State whether each of the following is true or false. If false, explain why.

  1. The sleep method does not consume processor time while a thread sleeps.
  2. Declaring a method synchronized guarantees that deadlock cannot occur.
  3. Java provides a powerful capability called multiple inheritance.
  4. Thread methods suspend and resume are deprecated.

15.4 Define each of the following terms.

  1. thread
  2. multithreading
  3. ready state
  4. blocked state
  5. preemptive scheduling
  6. Runnable interface
  7. monitor
  8. notify method
  9. producer/consumer relationship

15.5

  1. List each of the reasons stated in this chapter for using multithreading.
  2. List additional reasons for using multithreading.

15.6 List each of the three reasons given in the text for entering the blocked state. For each of these, describe how the program will normally leave the blocked state and enter the runnable state.

15.7 Distinguish between preemptive scheduling and nonpreemptive scheduling. Which does Java use?

15.8 What is timeslicing? Give a fundamental difference in how scheduling is performed on Java systems that support timeslicing vs. on Java systems that do not support timeslicing.

15.9 Why would a thread ever want to call yield?

15.10 What aspects of developing Java applets for the World Wide Web encourage applet designers to use yield and sleep abundantly?

15.11 If you choose to write your own start method, what must you be sure to do to make sure that your threads start up properly?

15.12 Distinguish among each of the following means of pausing threads:

  1. busy wait.
  2. sleep.
  3. blocking I/O.

15.13 Write a Java statement that tests if a thread is alive.

15.14

  1. What is multiple inheritance?
  2. Explain why Java does not offer multiple inheritance.
  3. What feature does Java offer instead of multiple inheritance?
  4. Explain the typical use of this feature.
  5. How does this feature differ from abstract classes?

15.15 Distinguish between the notions of extends and implements.

15.16 Discuss each of the following terms in the context of monitors:

  1. monitor.
  2. producer.
  3. consumer.
  4. wait.
  5. notify.
  6. InterruptedException.
  7. synchronized.

15.17 (Tortoise and the Hare) In the Chapter 7 exercises you were asked to simulate the legendary race of the tortoise and the hare. Implement a new version of that simulation, this time placing each of the animals in separate threads. At the start of the race call the start methods for each of the threads. Use wait, notify and notifyAll to synchronize the animals' activities.

15.18 (Multithreaded, Networked, Collaborative Applications) In Chapter 21 we will cover networking in Java. A multithreaded Java application can communicate concurrently with several host computers. This creates the possibility of being able to build some interesting kinds of collaborative applications. In anticipation of studying networking in Chapter 21, develop proposals for several possible multithreaded networked applications. After studying Chapter 21, implement some of those applications.

15.19 Write a Java program to demonstrate that as a high-priority thread executes, it will delay the execution of all lower-priority threads.

15.20 If your system supports timeslicing, write a Java program that demonstrates timeslicing among several equal-priority threads. Show that a lower-priority thread's execution is deferred by the timeslicing of the higher-priority threads.

15.21 Write a Java program that demonstrates a high-priority thread using sleep to give lower- priority threads a chance to run.

15.22 If your system does not support timeslicing, write a Java program that demonstrates two threads using yield to enable one another to execute.

15.23 Two problems that can occur in systems like Java, that allow threads to wait, are deadlock, in which one or more threads will wait forever for an event that cannot occur, and indefinite postponement, in which one or more threads will be delayed for some unpredictably long time. Give an example of how each of these problems can occur in a multithreaded Java program.

15.24 (Readers and Writers) This exercise asks you to develop a Java monitor to solve a famous problem in concurrency control. This problem was first discussed and solved by P. J. Courtois, F. Heymans and D. L. Parnas in their research paper, "Concurrent Control with Readers and Writers," Communications of the ACM, Vol. 14, No. 10, October 1971, pp. 667-668. The interested student might also want to read C. A. R. Hoare's seminal research paper on monitors, "Monitors: An Operating System Structuring Concept," Communications of the ACM, Vol. 17, No. 10, October 1974, pp. 549-557. Corrigendum, Communications of the ACM, Vol. 18, No. 2, February 1975, p. 95. [The readers and writers problem is discussed at length in Chapter 5 of the author's book: Deitel, H. M., Operating Systems, Reading, MA: Addison-Wesley, 1990.]

With multithreading, many threads can access shared data; as we have seen, access to shared data needs to be carefully synchronized to avoid corrupting the data.

Consider an airline reservation system in which many clients are attempting to book seats on particular flights between particular cities. All of the information about flights and seats is stored in a common database in memory. The database consists of many entries, each representing a seat on a particular flight for a particular day between particular cities. In a typical airline reservation scenario, the client will probe around in the database looking for the "optimal" flight to meet that client's needs. So a client may probe the database many times before deciding to try and book a particular flight. A seat that was available during this probing phase could easily be booked by someone else before the client has a chance to book it after deciding on it. In that case, when the client attempts to make the reservation, the client will discover that the data has changed and the flight is no longer available.

The client probing around the database is called a reader. The client attempting to book the flight is called a writer. Clearly, any number of readers can be probing shared data at once, but each writer needs exclusive access to the shared data to prevent the data from being corrupted.

Write a multithreaded Java program that launches multiple reader threads and multiple writer threads, each attempting to access a single reservation record. A writer thread has two possible transactions, makeReservation and cancelReservation. A reader has one possible transaction, queryReservation.

First implement a version of your program that allows unsynchronized access to the reservation record. Show how the integrity of the database can be corrupted. Next implement a version of your program that uses Java monitor synchronization with wait and notify to enforce a disciplined protocol for readers and writers accessing the shared reservation data. In particular, your program should allow multiple readers to access the shared data simultaneously when no writer is active. But if a writer is active, then no readers should be allowed to access the shared data.

Be careful. This problem has many subtleties. For example, what happens when there are several active readers and a writer wants to write? If we allow a steady stream of readers to arrive and share the data, they could indefinitely postpone the writer (who may become tired of waiting and take his or her business elsewhere). To solve this problem, you might decide to favor writers over readers. But here, too, there is a trap, because a steady stream of writers could then indefinitely postpone the waiting readers, and they, too, might choose to take their business elsewhere! Implement your monitor with the following methods: startReading, which is called by any reader who wants to begin accessing a reservation, stopReading to be called by any reader who has finished reading a reservation, startWriting to be called by any writer who wants to make a reservation and stopWriting to be called by any writer who has finished making a reservation.

15.25 Write a program that bounces a blue ball inside an applet. The ball should be initiated with a mousePressed event. When the ball hits the edge of the applet, the ball should bounce off the edge and continue in the opposite direction.

15.26 Modify the program of Exercise 15.25 to add a new ball each time the user clicks the mouse. Provide for a minimum of 20 balls. Randomly choose the color for each new ball.

15.27 Modify the program of Exercise 15.26 to add shadows. As a ball moves, draw a solid-black oval at the bottom of the applet. You may consider adding a 3D effect by increasing or decreasing the size of each ball when a ball hits the edge of the applet.

15.28 Modify the program of Exercise 15.25 or 15.26 to bounce the balls off each other when they collide.


Selected Answers

Included below are answers to approximately half the of the exercises in the Cyber Classroom. We are not able to include answers to every exercise because college faculty use these exercises in their classroom exams.


15.3 State whether each of the following is true or false. If false, explain why.

  1. The sleep method does not consume processor time while a thread sleeps.
    ANS: True.
  2. Declaring a method synchronized guarantees that deadlock cannot occur.
    ANS: False. Deadlocks can occur if the lock on an object is never released.
  3. Java provides a powerful capability called multiple inheritance.
    ANS: False. Java only provides single inheritance.
  4. Thread methods suspend and resume are deprecated.
    ANS: True.

15.4 Define each of the following terms.

  1. thread
    ANS: An individual execution context of a program.
  2. multithreading
    ANS: The ability of more than one thread to execute concurrently.
  3. ready state
    ANS: A state in which the thread is capable of running (if the processor becomes available).
  4. blocked state
    ANS: A state in which the thread cannot use the processor. For example, the blocked state occurs when the thread issues an I/O request.
  5. preemptive scheduling
    ANS: A thread of higher priority enters a running state and is assigned the processor. The thread "preempted" from the processor is placed back in the ready state according to its priority.
  6. Runnable interface
    ANS: An interface that provides a run method. By implementing the Runnable interface, any class can be executed as a separate thread.
  7. monitor
    ANS: A monitor "watches" shared data between threads. A monitor is responsible locking an object (i.e., allowing only one thread at a time to execute synchronized methods on the object).
  8. notify method
    ANS: Notifys a waiting thread that an object?s lock has been released and that the waiting thread can now attempt to obtain the lock for itself.
  9. producer/consumer relationship
    ANS: A relationship in which a producer and a consumer share common data. The producer typically wants to "produce" (add information) and the consumer wants to "eat" (remove information).

15.7 Distinguish between preemptive scheduling and nonpreemptive scheduling. Which does Java use?
ANS: With preemptive scheduling the thread with the highest priority runs when it has a chance to do so. This means that an executing lower-priority thread must yield the CPU to a thread with a higher priority (that is ready to run). Nonpreemptive scheduling is based on the order of the threads waiting for a processor. Higher priority threads will not force a lower priority thread from the CPU. Java uses preemptive scheduling.

15.9 Why would a thread ever want to call yield?
ANS: In an environment that does not use timeslicing, using the yield method will allow a waiting thread with the same priority to execute.

15.10 What aspects of developing Java applets for the World Wide Web encourage applet designers to use yield and sleep abundantly?
ANS: Not all systems use timeslicing, so using yield and sleep will allow threads of equal priority to share the processor on all systems.

15.14

  1. What is multiple inheritance?
    ANS: The ability to inherit from more than one class at a time.
  2. Explain why Java does not offer multiple inheritance.
    ANS: Multiple inheritance is too complex of a language issue
  3. What feature does Java offer instead of multiple inheritance?
    ANS: The ability to implement interfaces.
  4. Explain the typical use of this feature.
    ANS: A class already extends a class and needs a special capability such as threading. Since Java does not support multiple inheritance, additional features can come from the interface.
  5. How does this feature differ from abstract classes?
    ANS: An interface can only contain public abstract methods and final instance variables. In an abstract class, instance variables do not have to be final and methods may be implemented.

15.19

// Exercise 15.19 Solution
// Demo.java
// Program demonstrates high priority threads
import javax.swing.*;
import java.awt.*;
import java.awt.event.*;

public class Demo extends JFrame {
   private HighThread high;
   private LowThread low;
   private JTextArea output;

   public Demo()
   {
      super( "Demo" );
      output = new JTextArea( 10, 20 );
      getContentPane().add( output );
      setSize( 250, 200 );
      setVisible( true );

      high = new HighThread( output );
      high.start();

      low = new LowThread( output );
      low.start();
   }

   public static void main( String args[] )
   {
      Demo app = new Demo();
      app.addWindowListener(
         new WindowAdapter() {
            public void windowClosing( WindowEvent e )
            {
               System.exit( 0 );
            }
         }
      );

   }
}

class HighThread extends Thread {
   private JTextArea display;

   public HighThread( JTextArea a )
   {
      display = a;
      setPriority( Thread.MAX_PRIORITY );
   }

   public void run()
   {
      for ( int x = 1; x <= 5; x++ )
         display.append( "High Priority Thread!!!\n" );
   }
}

class LowThread extends Thread {
   private JTextArea display;

   public LowThread( JTextArea a )
   {
      display = a;
      setPriority( Thread.MIN_PRIORITY );
   }

   public void run()
   {
      for ( int y = 1; y <= 5; y++ )
         display.append( "Low Priority Thread!!!\n" );
   }
}

15.21

// Exercise 15.21 Solution
// Demo2.java
// Program demonstrates high priority threads
import javax.swing.*;
import java.awt.*;
import java.awt.event.*;

public class Demo2 extends JFrame {
   private HighThread high;
   private LowThread low;
   private JTextArea output;

   public Demo2()
   {
      super( "Demo2" );
      output = new JTextArea( 10, 20 );
      getContentPane().add( output );
      setSize( 250, 200 );
      setVisible( true );

      high = new HighThread( output );
      high.start();

      low = new LowThread( output );
      low.start();
   }

   public static void main( String args[] )
   {
      Demo2 app = new Demo2();
      app.addWindowListener(
         new WindowAdapter() {
            public void windowClosing( WindowEvent e )
            {
               System.exit( 0 );
            }
         }
      );

   }
}

class HighThread extends Thread {
   private JTextArea display;

   public HighThread( JTextArea a )
   {
      display = a;
      setPriority( Thread.MAX_PRIORITY );
   }

   public void run()
   {
      for ( int x = 1; x <= 5; x++ ) {
         try {
            sleep( ( int ) ( Math.random() * 200 ) );
         }
         catch ( Exception e ) {
            JOptionPane.showMessageDialog(
               null, e.toString(), "Exception",
               JOptionPane.ERROR_MESSAGE );
         }         
         display.append( "High Priority Thread\n" );
      }
   }
}

class LowThread extends Thread {
   private JTextArea display;

   public LowThread( JTextArea a )
   {
      display = a;
      setPriority( Thread.MIN_PRIORITY );
   }

   public void run()
   {
      for ( int y = 1; y <= 5; y++ )
         display.append( "Low Priority Thread!!!\n" );
   }
}

15.25

// Exercise 15.25 Solution
// Ball.java
// Program bounces a ball around the applet
import javax.swing.*;
import java.awt.*;
import java.awt.event.*;

public class Ball extends JApplet
          implements Runnable, MouseListener {
   private Thread blueBall;
   private boolean xUp, yUp, bouncing;
   private int x, y, xDx, yDy;

   public void init()
   {
      xUp = false;
      yUp = false;
      xDx = 1;
      yDy = 1;
      addMouseListener( this );
      bouncing = false;
   }

   public void mousePressed( MouseEvent e )
   {
      if ( blueBall == null ) {
         x = e.getX();
         y = e.getY();
         blueBall = new Thread( this );
         bouncing = true;
         blueBall.start();
      }
   }

   public void stop()
   {
      if ( blueBall != null ) {
         blueBall = null;
      }
   }

   public void paint( Graphics g )
   {
      if ( bouncing ) {
         g.setColor( Color.blue );
         g.fillOval( x, y, 10, 10 );
      }
   }

   public void run()
   {
      while ( true ) {

         try {
            blueBall.sleep( 100 );
         }
         catch ( Exception e ) {
            System.err.println( "Exception: " + e.toString() );
         }

         if ( xUp == true )
            x += xDx;
         else
            x -= xDx;

         if ( yUp == true )
            y += yDy;
         else
            y -= yDy;

         if ( y <= 0 ) {
            yUp = true;            
            yDy = ( int ) ( Math.random() * 5 + 2 );
         }
         else if ( y >= 190 ) {
            yDy = ( int ) ( Math.random() * 5 + 2 );
            yUp = false;
         }

         if ( x <= 0 ) {
            xUp = true;
            xDx = ( int ) ( Math.random() * 5 + 2 );
         }
         else if ( x >= 190 ) {
            xUp = false;
            xDx = ( int ) ( Math.random() * 5 + 2 );
         }

         repaint();
      }
   }

   public void mouseExited( MouseEvent e ) {}
   public void mouseClicked( MouseEvent e ) {}
   public void mouseReleased( MouseEvent e ) {}
   public void mouseEntered( MouseEvent e ) {}     
}