Threads and Concurrent Programming

Threads may be seen as methods that execute at "the same time" as other methods. Normally, we think sequentially when writing a computer program. From this perspective, only one thing executes at a time. However, with today's multi-core processors, it is possible to literally have several things going on at the very same time while sharing the same memory. There are lots of ways that this is done in the real world, and this chapter goes over them in a way that you can apply to your own projects.

14.5 Using Threads to Improve Interface Responsiveness

Single-Threaded Design

It’s always a good idea that the interface be responsive to user input, but sometimes it is crucial to an application. For example, suppose a psychology experiment is trying to measure how quickly a user responds to a certain stimulus presented by a program. Obviously, for this kind of application, the program should take action as soon as the user clicks a button to indicate a response to the stimulus. Let’s work through an appropriate program design for the experiment. First, we will formally state the situation and describe what the program should do. Then, we will examine the components that would make up an effective program.

Problem Statement

Annotation 2020-03-24 213621A psychologist is conducting a psychometric experiment to measure user response to a visual cue and asks you to create the following program. The program should have two buttons. When the Draw button is clicked, the program begins drawing thousands of black dots at random locations within a rectangular region of the screen (Fig. 14.7). After a random time interval, the program begins drawing red dots. This change corresponds to the presentation of the stimulus. As soon as the stimulus is presented the user is supposed to click on a Clear button, which clears the drawing area. To provide a measure of the user’s reaction time, the program should report how many red dots were drawn before the user clicked the Clear button.

Annotation 2020-03-24 213726

Figure 14.8: GUI design for the dot-drawing

ogram. Figure 14.8 shows a design for this program’s GUI. It contains a control JPanel that contains the two JButtons. The dots are drawn on a JPanel, which is positioned in the center of a BorderLayout design. 

Problem Decomposition 

This program should be decomposed into two classes, a GUI to handle the user interface and a drawing class to manage the drawing. The main features of its classes are as follows: 

  • RandomDotGUI Class: This class manages the user interface, responding to user actions by calling methods of the Dotty class (Fig. 14.9). 
  • Dotty Class: This class contains draw() and clear() methods for drawing on the GUI’s drawing panel (Fig. 14.10)
Annotation 2020-03-24 214017

The RandomDotGUI Class
The implementation of RandomDotGUI is shown in Figure 14.11.

Annotation 2020-03-24 215135Annotation 2020-03-24 215226

The GUI arranges the control and drawing panels in a BorderLayout and listens for action events on its JButtons. When the user clicks the Draw button, the GUI’s actionPerformed() method will create a new Dotty instance and call its draw() method:

Annotation 2020-03-24 214332

Note that Dotty is passed a reference to the drawing canvas as well as the number of dots to be drawn. When the user clicks the Clear button, the GUI should call the dotty.clear() method. Of course, the important question is, how responsive will the GUI be to the user's action?

The Dotty Class 

The purpose of the Dotty class will be to draw the dots and to report how many red dots were drawn before the canvas was cleared. Because it will be passed a reference to the drawing panel and the number of dots to draw, the Dotty class will need instance variables to store these two values. It will also need a variable to keep track of how many dots were drawn. Finally, since it will be drawing within a fixed rectangle on the panel, the reference coordinates and dimensions of the drawing area are declared as class constants. 

The Dotty() constructor method will be passed a reference to a drawing panel as well as the number of dots to be drawn and will merely assign these parameters to its instance variables. In addition to it constructor method, the Dotty class will have public draw() and clear() methods, which will be called from the GUI. The draw() method will use a loop to draw random dots. The clear() will clear the canvas and report the number of dots drawn.

The complete implementation of Dotty is shown in Figure 14.12. Note how its draw() method is designed. The drawing loop is bounded by the number of dots to be drawn. On each iteration, the draw() method picks a random location within the rectangle defined by the coordinates (HREF,VREF) and (HREF+LEN, VREF+LEN), and draws a dot there. On each iteration it also generates a random number. If the random number is less than 0.001, it changes the drawing color to red and keeps track of the number of dots drawn up to that point.

Annotation 2020-03-24 215527Annotation 2020-03-24 215618

Figure 14.12: The Dotty class, single-threaded version.

The problem with this design is that as long as the draw() method is executing, the program will be unable to respond to the GUI’s Clear button. In a single-threaded design, both the GUI and dotty are combined into a single thread of execution (Fig. 14.13). When the user clicks the Draw button, the GUI’s actionPerformed() method is invoked. It then invokes Dotty’s draw() method, which must run to completion before anything else can be done. If the user clicks the Clear button while the dots are being drawn, the GUI won’t be able to get to this until all the dots are drawn.

Annotation 2020-03-24 215739

If you run this program with nDots set to 10,000, the program will not clear the drawing panel until all 10,000 dots are drawn, no matter when the Clear button is pressed. Therefore, the values reported for the user’s reaction time will be wrong. Obviously, since it is so unresponsive to user input, this design completely fails to satisfy the program’s specifications.

Annotation 2020-03-24 220040


EXERCISE 14.6 Suppose the Java Virtual Machine (JVM) was single threaded and your program got stuck in an infinite loop. Would you be able to break out of the loop by typing some special command (such as Control-C) from the keyboard?