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.7 CASE STUDY: The Game of Pong

Implementation of the Pong Program

We begin our discussion of the program’s implementation with the Paddle class implementation (Fig. 14.31).

Class constants, HEIGHT and WIDTH are used to define the size of the Paddle, which is represented on the frame as a simple rectangle. The frame will use the Graphics.fillRect() method to draw the paddle:

Annotation 2020-03-25 210545

Note how the frame uses the paddle’s getX() and getY() methods to get the paddle’s current location.

The class constants DELTA and BORDER are used to control the paddle’s movement. DELTA represents the number of pixels that the paddle moves on each move up or down, and BORDER is used with gameAreaHeight to keep the paddle within the drawing area. The moveUp() and moveDown() methods are called by the frame each time the user presses an up- or down-arrow key. They simply change the paddle’s location by DELTA pixels up or down.

Annotation 2020-03-25 210759Annotation 2020-03-25 210907

The Ball class (Fig. 14.32) uses the class constant SIZE to determine the size of the oval that represents the ball, drawn by the frame as follows:

Annotation 2020-03-25 211016

As with the paddle, the frame uses the ball’s getX() and getY() method to determine the ball’s current location.

Unlike the paddle, however, the ball moves autonomously. Its run() method, which is inherited from its Thread superclass, repeatedly moves the ball, draws the ball, and then sleeps for a brief interval (to slow down the speed of the ball’s apparent motion). The run() method itself is quite simple because it consists of a short loop. We will deal with the details of how the ball is painted on the frame when we discuss the frame itself.

Annotation 2020-03-25 211209Annotation 2020-03-25 211323

The most complex method in the Ball class is the move() method. This is the method that controls the ball’s movement within the boundaries of the frame’s drawing area. This method begins by moving the ball by one pixel left, right, up, or down by adjusting the values of its locationX and locationY coordinates:

Annotation 2020-03-25 211534

The directionX and directionY variables are set to either +1 or 1, depending on whether the ball is moving left or right, up or down. After the ball is moved, the method uses a sequence of if statements to check whether the ball is touching one of the walls or the paddle. If the ball is in contact with the top, left, or bottom walls or the paddle, its direction is changed by reversing the value of the directionX or directionY variable. The direction changes depend on whether the ball has touched a horizontal or vertical wall. When the ball touches the right wall, having missed the paddle, it passes through the right wall and re-emerges from the left wall going in the same direction.

Note how the frame method, ballHitsPaddle() is used to determine whether the ball has hit the paddle. This is necessary because only the frame knows the locations of both the ball and the paddle.