[ Pobierz całość w formacie PDF ]
.Conditions, wait(),and notify()Threads are usually coordinated using a concept known as a condition,or a condition variable.A condition is a logical statementthat must hold true in order for a thread to proceed; if the conditiondoes not hold true, the thread must wait for the condition tobecome true before continuing.In Java, this pattern is usuallyexpressed as follows:while ( ! the_condition_I_am_waiting_for ) {wait();}First, check to see whether the desired condition is already true.If it is true, there is no need to wait.If the condition is notyet true, call the wait()method.When wait() ends,recheck the condition to make sure that it is now true.Invoking wait() on an objectpauses the current thread and adds the thread to the conditionvariable wait queue of the object's monitor.This queue containsa list of all the threads that are currently blocked inside wait()on that object.The thread is not removed from the wait queueuntil notify() is invokedon that object from a different thread.A call to notify()wakes a single waiting thread, notifying the thread that a conditionof the object has changed.There are two additional varieties of the wait()method.The first version takes a single parameter-a timeout valuein milliseconds.The second version has two parameters-a moreprecise timeout value, specified in milliseconds and nanoseconds.These methods are used when you do not want to wait indefinitelyfor an event.If you want to abandon the wait after a fixed periodof time (referred to as timing out), you should use eitherof the following methods:wait(long milliseconds);wait(long milliseconds, intnanoseconds);Unfortunately, these methods do not provide a means to determinehow the wait() was ended-whethera notify() occurred or whetherit timed out.This is not a big problem, however, because youcan recheck the wait condition and the system time to determinewhich event has occurred.CautionIn the 1.2 JDK, the wait(int millisecond, int nanosecond) method uses the nano- second parameter to round the millisecond parameter to the nearest millisecond.Waiting is not yet supported in nanosecond granularity.The wait() and notify()methods must be invoked from within a synchronizedmethod or from within a synchronizedstatement.This requirement is discussed in further detail in"Monitor Ownership," later in this chapter.A Thread Coordination ExampleA classic example of thread coordination used in many computerscience texts is the bounded buffer problem.This probleminvolves using a fixed-size memory buffer to communicate betweentwo processes or threads.To solve this problem, you must coordinatethe reader and writer threads so that the following are true:When the writer thread attempts to writeto a full buffer, the writer is suspended until some items areremoved from the buffer.When the reader thread removes items fromthe full buffer, the writer thread is notified of the buffer'schanged condition and may continue writing.When the reader thread attempts to readfrom an empty buffer, the reader is suspended until some itemsare added to the buffer.When the writer adds items to the emptybuffer, the reader thread is notified of the buffer's changedcondition and may continue reading.The following class listings demonstrate a Java implementationof the bounded buffer problem.There are three main classes inthis example: the Producer,the Consumer, and the Buffer.Let's start with the Producer:public class Producer implements Runnable {private Buffer buffer;public Producer(Buffer b) {buffer = b;}public void run() {for (int i=0; i<250; i++) {buffer.put((char)('A' + (i%26))); // write to the buffer}}}The Producer class implementsthe Runnable interface (whichshould give you a hint that it will be used in a Thread).When the Producer's run()method is invoked, 250 characters are written in rapid successionto a buffer.The Consumer class is assimple as the Producer:public class Consumer implements Runnable {private Buffer buffer;public Consumer(Buffer b) {buffer = b;}public void run() {for (int i=0; i<250; i++) {System.out.println(buffer.get()); // read from the buffer}}}The Consumer is also a Runnableinterface.Its run() methodgreedily reads 250 characters from a buffer.The Buffer class has beenmentioned already, including two of its methods: put(char)and get().Listing 9
[ Pobierz całość w formacie PDF ]