站内搜索: 请输入搜索关键词
当前页面: 在线文档首页 > Java Tutorial 5.0 英文版

The Producer/Consumer Example - Java Tutorial 5.0 英文版

The JavaTM Tutorial
Previous Page Lesson Contents Next Page Start of Tutorial > Start of Trail > Start of Lesson Search
Feedback Form

Trail: Essential Java Classes
Lesson: Threads: Doing Two or More Tasks at Once

The Producer/Consumer Example

In this example, the Producer (in a .java source file) generates an integer between 0 and 9 (inclusive), then stores it in a CubbyHole (in a .java source file) object. To make the synchronization problem more interesting, the Producer sleeps for a random amount of time between 0 and 100 milliseconds before repeating the number-generating cycle.
public 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(number, i);
            try {
                sleep((int)(Math.random() * 100));
            } catch (InterruptedException e) { }
        }
    }
}
The Consumer (in a .java source file) consumes all integers from the CubbyHole (the exact same object into which the Producer put the integers in the first place) as quickly as they become available.
public 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(number);
        }
    }
}
The Producer and Consumer examples share data through a common CubbyHole object. Although, ideally, Consumer will get each value produced once and only once, neither Producer nor Consumer makes any effort whatsoever to ensure that this happens. The synchronization between these two threads occurs at a lower level within the get and put methods of the CubbyHole object. Assume for a moment, however, that the two threads make no arrangements for synchronization; let's discuss the potential problems that might arise from this.

One problem arises when the Producer is quicker than the Consumer and generates two numbers before the Consumer has a chance to consume the first one. In this situation, the Consumer misses a number. Part of the output might look like the following figure.

Consumer misses number.

Consumer misses number.

Another problem might arise when the Consumer is quicker than the Producer and consumes the same value twice. In this situation, the Consumer might produce the output shown in the following figure.

Consumer gets the same number twice.

Consumer gets the same number twice.

Either way, the result is wrong because the Consumer should get each integer produced by the Producer exactly once. A problem like this is called a race condition. A race condition is a situation in which two or more threads or processes are reading or writing some shared data, and the final result depends on the timing of how the threads are scheduled. Race conditions can lead to unpredictable results and subtle program bugs. Race conditions in the producer-consumer example are prevented by having storage of a new integer in the CubbyHole by the Producer synchronized with retrieval of an integer from the CubbyHole by the Consumer. The activities of the Producer and the Consumer must be synchronized in two ways.

First, the two threads must not simultaneously access the CubbyHole. A 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 be blocked until the object is unlocked.

Second, the two threads must do some simple coordination. That is, the Producer must have a way to indicate to the Consumer that the value is ready, and the Consumer must have a way to indicate that the value has been retrieved. The Object class provides a collection of methods — wait, notify, and notifyAll — to help threads wait for a condition and to notify other threads when that condition changes.


Previous Page Lesson Contents Next Page Start of Tutorial > Start of Trail > Start of Lesson Search
Feedback Form

Copyright 1995-2005 Sun Microsystems, Inc. All rights reserved.