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.
15.4 Define each of the following terms.
15.5
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:
15.13 Write a Java statement that tests if a thread is alive.
15.15 Distinguish between the notions of extends and implements.
15.16 Discuss each of the following terms in the context of monitors:
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.
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.
15.4 Define each of the following terms.
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.
// 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" ); } }
// 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" ); } }
// 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 ) {} }