Thursday, July 30, 2009

Producer-Consumer Example

The following example is an implementation of the Producer-Consumer problem. A class which provides the methods for generating and consuming an integer value is separated from the Producer and the Consumer thread classes.

class SharedData {
int data;
synchronized void set(int value) {
System.out.println("Generate " + value);
data = value;
}
synchronized int get() {
System.out.println("Get " + data);
return data;
}
}

class Producer implements Runnable {
SharedData sd;
Producer(SharedData sd) {
this.sd = sd;
new Thread(this, "Producer").start();
}
public void run() {
for (int i = 0; i < 10; i++) {
sd.set((int)(Math.random()*100));
}
}
}

class Consumer implements Runnable {
SharedData sd;
Consumer(SharedData sd) {
this.sd = sd;
new Thread(this, "Consumer").start();
}
public void run() {
for (int i = 0; i < 10 ; i++) {
sd.get();
}
}
}

class TestProducerConsumer {
public static void main(String args[]) throws Exception {
SharedData sd = new SharedData();
new Producer(sd);
new Consumer(sd);
}
}

Here is a sample output of the program.

Generate 8
Generate 45
Generate 52
Generate 65
Get 65
Generate 23
Get 23
Generate 49
Get 49
Generate 35
Get 35
Generate 39
Get 39
Generate 85
Get 85
Get 85
Get 85
Generate 35
Get 35
Get 35

This is not what we wanted the program to do. For every value produced by the producer, we expect the consumer to get each value. Here is the output we expect instead.

Generate 76
Get 76
Generate 25
Get 25
Generate 34
Get 34
Generate 84
Get 84
Generate 48
Get 48
Generate 29
Get 29
Generate 26
Get 26
Generate 86
Get 86
Generate 65
Get 65
Generate 38
Get 38
Generate 46
Get 46

To fix the problem with this code, we use the methods for interthread communication.
The following implementation of the Producer-Consumer problem uses the methods for interthread communication.

class SharedData {
int data;
boolean valueSet = false;
synchronized void set(int value) {
if (valueSet) { //has just produced a value
try {
wait();
} catch (InterruptedException ie) {
}
}
System.out.println("Generate " + value);
data = value;
valueSet = true;
notify();
}
synchronized int get() {
if (!valueSet) { //producer hasn't set a value yet
try {
wait();
} catch (InterruptedException ie) {
}
}
System.out.println("Get " + data);
valueSet = false;
notify();
return data;
}
}

/* The remaining part of the code doesn't change. */
class Producer implements Runnable {
SharedData sd;
Producer(SharedData sd) {
this.sd = sd;
new Thread(this, "Producer").start();
}
public void run() {
for (int i = 0; i < 10; i++) {
sd.set((int)(Math.random()*100));
}
}
}

class Consumer implements Runnable {
SharedData sd;
Consumer(SharedData sd) {
this.sd = sd;
new Thread(this, "Consumer").start();
}
public void run() {
for (int i = 0; i < 10 ; i++) {
sd.get();
}
}
}

class TestProducerConsumer {
public static void main(String args[]) throws Exception {
SharedData sd = new SharedData();
new Producer(sd);
new Consumer(sd);
}
}

No comments:

Post a Comment