26.07.2013 Views

Java How to Program Fourth Edition - DCC

Java How to Program Fourth Edition - DCC

Java How to Program Fourth Edition - DCC

SHOW MORE
SHOW LESS

You also want an ePaper? Increase the reach of your titles

YUMPU automatically turns print PDFs into web optimized ePapers that Google loves.

Chapter 15 Multithreading 849<br />

Moni<strong>to</strong>r objects maintain a list of all threads waiting <strong>to</strong> enter the moni<strong>to</strong>r object <strong>to</strong> execute<br />

synchronized methods. A thread is inserted in the list and waits for the object if<br />

that thread calls a synchronized method of the object while another thread is already<br />

executing in a synchronized method of that object. A thread also is inserted in the list<br />

if the thread calls wait while operating inside the object. <strong>How</strong>ever, it is important <strong>to</strong> distinguish<br />

between waiting threads that blocked because the moni<strong>to</strong>r was busy and threads<br />

that explicitly called wait inside the moni<strong>to</strong>r. Upon completion of a synchronized<br />

method, outside threads that blocked because the moni<strong>to</strong>r was busy can proceed <strong>to</strong> enter the<br />

object. Threads that explicitly invoked wait can proceed only when notified via a call by<br />

another thread <strong>to</strong> notify or notifyAll. When it is acceptable for a waiting thread <strong>to</strong><br />

proceed, the scheduler selects the thread with the highest priority.<br />

Common <strong>Program</strong>ming Error 15.2<br />

It is an error if a thread issues a wait, a notify or a notifyAll on an object without<br />

having acquired a lock for the object. This causes an IllegalMoni<strong>to</strong>rState-<br />

Exception. 15.2<br />

15.6 Producer/Consumer Relationship without Thread<br />

Synchronization<br />

In a producer/consumer relationship, a producer thread calling a produce method may<br />

see that the consumer thread has not read the last message from a shared region of memory<br />

called a buffer, so the producer thread will call wait. When a consumer thread reads<br />

the message, it will call notify <strong>to</strong> allow a waiting producer <strong>to</strong> proceed. When a consumer<br />

thread enters the moni<strong>to</strong>r and finds the buffer empty, it calls wait. A producer<br />

finding the buffer empty writes <strong>to</strong> the buffer, then calls notify so a waiting consumer<br />

can proceed.<br />

Shared data can get corrupted if we do not synchronize access among multiple threads.<br />

Consider a producer/consumer relationship in which a producer thread deposits a sequence<br />

of numbers (we use 1, 2, 3, …) in<strong>to</strong> a slot of shared memory. The consumer thread reads<br />

this data from the shared memory and prints it. We print what the producer produces as it<br />

produces it and what the consumer consumes as it consumes it. The program of Fig. 15.4–<br />

Fig. 15.7 demonstrates a producer and a consumer accessing a single shared cell of memory<br />

(int variable sharedInt in Fig. 15.6) without any synchronization. The threads are not<br />

synchronized, so data can be lost if the producer places new data in<strong>to</strong> the slot before the<br />

consumer consumes the previous data. Also, data can be “doubled” if the consumer consumes<br />

data again before the producer produces the next item. To show these possibilities,<br />

the consumer thread in this example keeps a <strong>to</strong>tal of all the values it reads. The producer<br />

thread produces values from 1 <strong>to</strong> 10. If the consumer reads each value produced only once,<br />

the <strong>to</strong>tal would be 55. <strong>How</strong>ever, if you execute this program several times, you will see that<br />

the <strong>to</strong>tal is rarely, if ever, 55.<br />

The program consists of four classes—ProduceInteger (Fig. 15.4), ConsumeInteger<br />

(Fig. 15.5), HoldIntegerUnsynchronized (Fig. 15.6) and<br />

SharedCell (Fig. 15.7).<br />

Class ProduceInteger (Fig. 15.4)—a subclass of Thread—consists of instance<br />

variable sharedObject (line 4), a construc<strong>to</strong>r (lines 7–11) and a run method (lines 15–<br />

37). The construc<strong>to</strong>r initializes instance variable sharedObject (line 10) <strong>to</strong> refer <strong>to</strong> the

Hooray! Your file is uploaded and ready to be published.

Saved successfully!

Ooh no, something went wrong!