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.6 CASE STUDY: Cooperating Threads
Design: The TakeANumber Class
The TakeANumber class must track two things: Which customer will be served next, and which waiting number the next customer will be given. This suggests that it should have at least two public methods:
nextNumber(), which will be used by customers to get their waiting numbers, and nextCustomer(), which will be used by the clerk to determine who should be served (Fig. 14.18). Each of these methods will simply retrieve the values of the instance variables, next and serving, which keep track
of these two values. As part of the object’s state, these variables should be private.
How should we make this TakeANumber object accessible to all of
the other objects—that is, to all of the customers and to the clerk? The
easiest way to do that is to have the main program pass a reference to
the TakeANumber when it constructs the Customers and the Clerk.
They can each store the reference as an instance variable. In this way,
all the objects in the simulation can share a TakeANumber object as a common resource. Our design considerations lead to the definition of the
TakeANumber class shown in Figure 14.1
Note that the nextNumber() method is declared synchronized. As
we will discuss in more detail, this ensures that only one customer at a
time can take a number. Once a thread begins executing a synchronized
method, no other thread can execute that method until the first thread finishes. This is important because, otherwise, several Customers could call the nextNumber method at the same time. It’s important that the
customer threads have access only one at a time, also called mutually exclusive access to the TakeANumber object. This form of mutual exclusion
is important for the correctness of the simulation.
EXERCISE 14.9 What is the analogue to mutual exclusion in the realworld bakery situation?