Saturday, 28 January 2012

Inter Thread Communication in Java with Example

I hope you have gone through  my previous post  Inter-Thread Communications in Java  before reading it.

We have a classic 'Producer-Consumer' problem to explain the use of Inter-Thread communications in java,where one thread is producing some data and another is consuming it .The producer has to wait until the consumer is finished before it generates more data.

Let us start with an incorrect implementation of  Producer-Consumer problem, where we are just using the mercy of synchronized method .


// An incorrect implementation of a producer and consumer.
class Q {
    int n;

    synchronized int get() {
        System.out.println("Got: " + n);
        return n;
    }

    synchronized void put(int n) {
        this.n = n;
        System.out.println("Put: " + n);
    }
}


class Producer implements Runnable {
    Q q;

    Producer(Q q) {
        this.q = q;
        new Thread(this, "Producer").start();
    }

    public void run() {
        int i = 0;
        while (true) {
            q.put(++i);
        }
    }
}

class Consumer implements Runnable {
    Q q;

    Consumer(Q q) {
        this.q = q;
        new Thread(this, "Consumer").start();
    }

    public void run() {
        while (true) {
            q.get();
        }
    }
}

public class Main {

    public static void main(String args[]) {
        Q q = new Q();
        new Producer(q);
        new Consumer(q);
    }
}

Although the put( ) and get( ) methods on Q are synchronized, nothing stops the producer from producing more things than the consumer can use and nothing stops the consumer from using the same product more than once.
Thus,you will get a wrong output as shown below.

Put: 1
Got: 1
Got: 1
Got: 1
Put: 2
Put: 3
Put: 4
Put: 5
Put: 6
Got: 6

Here Consumer used the same product, product-1 thrice and Consumer didn't get a chance to use the products, Product-2,Product-3,Product-4 and Product-5.

Now we came to know that ,with the only use of synchronized, can't do proper communication between multiple threads.Don't worry ,java is rich enough to provide a solution for this issue,providing three methods ,wait(),notify() and notifyAll() for Inter-Thread Communication.

Let us try the Producer-Consumer problem with the wait() and notify() methods.

// A correct implementation of a producer and consumer.
class Q {
    int n;
    boolean isQueueEmpty = true;

    synchronized int get() {
        if (isQueueEmpty)
            try {
                wait();
            } catch (InterruptedException e) {
                System.out.println("InterruptedException caught");
            }
        System.out.println("Got: " + n);
        isQueueEmpty = true;
        notify();
        return n;
    }

    synchronized void put(int n) {
        if (!isQueueEmpty)
            try {
                wait();
            } catch (InterruptedException e) {
                System.out.println("InterruptedException caught");
            }
        this.n = n;
        isQueueEmpty = false;
        System.out.println("Put: " + n);
        notify();
    }
}

class Producer implements Runnable {
    Q q;

    Producer(Q q) {
        this.q = q;
        new Thread(this, "Producer").start();
    }

    public void run() {
        int i = 0;
        while (true) {
            q.put(i++);
        }
    }
}

class Consumer implements Runnable {
    Q q;

    Consumer(Q q) {
        this.q = q;
        new Thread(this, "Consumer").start();
    }

    public void run() {
        while (true) {
            q.get();
        }
    }
}

public class Main {

    public static void main(String args[]) {
        Q q = new Q();
        new Producer(q);
        new Consumer(q);
    }
}

Here you will get the expected result as shown below

Put: 1
Got: 1
Put: 2
Got: 2
Put: 3
Got: 3
Put: 4
Got: 4
Put: 5
Got: 5

We can see that Producer is not overrunning the Consumer and the Consumer is not using the same product twice.

Summary

We can conclude the above example as given below




PRODUCER CONSUMER NOTE
STEP 1 Producing.... Waiting for lock Producer got lock on Queue
STEP 2 Produced one product and invoked wait() Producer released lock on Queue
STEP 3 Waiting for lock Consuming.... Consumer got lock on Queue
STEP 4 Consumed one product and invoked notify() Consumer released lock on Queue
 

No comments:

Post a Comment