|
|
Start of Tutorial > Start of Trail > Start of Lesson |
Search
Feedback Form |
TheProducergenerates an integer between 0 and 9 (inclusive), stores it in a
CubbyHoleobject, and prints the generated number. To make the synchronization problem more interesting, the
Producersleeps for a random amount of time between 0 and 100 milliseconds before repeating the number generating cycle:Thepublic class Producer extends Thread { private CubbyHole cubbyhole; private int number; public Producer(CubbyHole c, int number) { cubbyhole = c; this.number = number; } public void run() { for (int i = 0; i < 10; i++) { cubbyhole.put(i); System.out.println("Producer #" + this.number + " put: " + i); try { sleep((int)(Math.random() * 100)); } catch (InterruptedException e) { } } } }Consumer, being ravenous, consumes all integers from the
CubbyHole(the exact same object into which theProducerput the integers in the first place) as quickly as they become available.Thepublic class Consumer extends Thread { private CubbyHole cubbyhole; private int number; public Consumer(CubbyHole c, int number) { cubbyhole = c; this.number = number; } public void run() { int value = 0; for (int i = 0; i < 10; i++) { value = cubbyhole.get(); System.out.println("Consumer #" + this.number + " got: " + value); } } }ProducerandConsumerin this example share data through a commonCubbyHoleobject. And you will note that neither theProducernor theConsumermakes any effort whatsoever to ensure that theConsumeris getting each value produced once and only once. The synchronization between these two threads actually occurs at a lower level, within thegetandputmethods of theCubbyHoleobject. However, let's assume for a moment that these two threads make no arrangements for synchronization and talk about the potential problems that might arise in that situation.One problem arises when the
Produceris quicker than theConsumerand generates two numbers before theConsumerhas a chance to consume the first one. Thus theConsumerwould skip a number. Part of the output might look like this:Another problem that might arise is when the. . . Consumer #1 got: 3 Producer #1 put: 4 Producer #1 put: 5 Consumer #1 got: 5 . . .Consumeris quicker than theProducerand consumes the same value twice. In this situation, theConsumerwould print the same value twice and might produce output that looked like this:Either way, the result is wrong. You want the. . . Producer #1 put: 4 Consumer #1 got: 4 Consumer #1 got: 4 Producer #1 put: 5 . . .Consumerto get each integer produced by theProducerexactly once. Problems such as those just described are called race conditions. They arise from multiple, asynchronously executing threads trying to access a single object at the same time and getting the wrong result.Race conditions in the producer/consumer example are prevented by having the storage of a new integer into the
CubbyHoleby theProducerbe synchronized with the retrieval of an integer from theCubbyHoleby theConsumer. TheConsumermust consume each integer exactly once.The activities of the
ProducerandConsumermust be synchronized in two ways. First, the two threads must not simultaneously access theCubbyHole. A Java thread can prevent this from happening by locking an object. When an object is locked by one thread and another thread tries to call a synchronized method on the same object, the second thread will block until the object is unlocked. Locking an Object discusses this.And second, the two threads must do some simple coordination. That is, the
Producermust have some way to indicate to theConsumerthat the value is ready and theConsumermust have some way to indicate that the value has been retrieved. TheThreadclass provides a collection of methods--wait,notify, andnotifyAll--to help threads wait for a condition and notify other threads of when that condition changes. Using thenotifyAllandwaitMethods has more information.
Here's a small stand-aloneJava applicationthat creates a
CubbyHoleobject, aProducer, aConsumer, and then starts both theProducerand theConsumer.public class ProducerConsumerTest { public static void main(String[] args) { CubbyHole c = new CubbyHole(); Producer p1 = new Producer(c, 1); Consumer c1 = new Consumer(c, 1); p1.start(); c1.start(); } }
Here's the output of ProducerConsumerTest.Producer #1 put: 0 Consumer #1 got: 0 Producer #1 put: 1 Consumer #1 got: 1 Producer #1 put: 2 Consumer #1 got: 2 Producer #1 put: 3 Consumer #1 got: 3 Producer #1 put: 4 Consumer #1 got: 4 Producer #1 put: 5 Consumer #1 got: 5 Producer #1 put: 6 Consumer #1 got: 6 Producer #1 put: 7 Consumer #1 got: 7 Producer #1 put: 8 Consumer #1 got: 8 Producer #1 put: 9 Consumer #1 got: 9
|
|
Start of Tutorial > Start of Trail > Start of Lesson |
Search
Feedback Form |
Copyright 1995-2004 Sun Microsystems, Inc. All rights reserved.