Java Interthread Communiction

Category: Java   Tags: Java, Java Thread, Java MultiThread, Thread Synchronization, Thread Communication, Java Concurrent Collection

Java use three method for interthread communication:

  • wait(): It tells the calling thread to leave the monitor and sleep until some other thread enters the same monitor and calls notify() or notifyAll() method.
  • notify(): It will wake up the thread that called wait() on the same object.
  • notifyAll(): It will wake up all thread that called wait() on the same object.

Producer and consumer is the most popular example to show interthread communication. The below example shows an incorrect implementation of a producer and consumer without using wait() and notify():

JavaThreadProducerConsumerExample.java

                            package com.tutorial.javabasic;

                            class Resource {
                                int data;

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

                                synchronized void put(int d) {
                                    System.out.println("Putting: " + data);
                                    data = d;
                                }
                            }

                            class Producer implements Runnable {

                                Resource resource;

                                Producer(Resource r) {
                                    resource = r;
                                    new Thread(this).start();
                                }

                                @Override
                                public void run() {
                                    for(int i=1; i<=5; i++) {
                                        resource.put(i);
                                    }
                                }
                            }

                            class Consumer implements Runnable {

                                Resource resource;

                                Consumer(Resource r) {
                                    resource = r;
                                    new Thread(this).start();
                                }

                                @Override
                                public void run() {
                                    for(int i=1; i<=5; i++) {
                                        resource.get();
                                    }
                                }
                            }

                            public class JavaThreadProducerConsumerExample {

                                public static void main(String s[]) {
                                    Resource r = new Resource();
                                    new Producer(r);
                                    new Consumer(r);
                                }
                            }
                        

Here get() and put() are synchronized on Resource. In this code there is no way that will stop the producer from overrunning the consumer, and also consumer can consume the same value twice.

Output:

                            Putting: 0
                            Putting: 1
                            Putting: 2
                            Putting: 3
                            Putting: 4
                            Getting: 5
                            Getting: 5
                            Getting: 5
                            Getting: 5
                            Getting: 5
                          

Here is the correct version:

JavaThreadProducerConsumerExample.java

                            package com.tutorial.javabasic;

                            class Resource {

                                int data;
                                boolean hasValue = false;

                                synchronized int get() {
                                    while (!hasValue) {
                                        try {
                                            wait();
                                        } catch (InterruptedException ex) {
                                            ex.printStackTrace();
                                        }
                                    }
                                    System.out.println("Getting: " + data);
                                    hasValue = false;
                                    notify();
                                    return data;
                                }

                                synchronized void put(int d) {
                                    while (hasValue) {
                                        try {
                                            wait();
                                        } catch (InterruptedException ex) {
                                            ex.printStackTrace();
                                        }
                                    }
                                    data = d;
                                    hasValue = true;
                                    System.out.println("Putting: " + data);
                                    notify();
                                }
                            }

                            class Producer implements Runnable {

                                Resource resource;

                                Producer(Resource r) {
                                    resource = r;
                                    new Thread(this).start();
                                }

                                @Override
                                public void run() {
                                    for (int i = 1; i <= 5; i++) {
                                        resource.put(i);
                                    }
                                }
                            }

                            class Consumer implements Runnable {

                                Resource resource;

                                Consumer(Resource r) {
                                    resource = r;
                                    new Thread(this).start();
                                }

                                @Override
                                public void run() {
                                    for (int i = 1; i <= 5; i++) {
                                        resource.get();
                                    }
                                }
                            }

                            public class JavaThreadProducerConsumerExample {

                                public static void main(String s[]) {
                                    Resource r = new Resource();
                                    new Producer(r);
                                    new Consumer(r);
                                }
                            }
                        

Output:

                            Putting: 1
                            Getting: 1
                            Putting: 2
                            Getting: 2
                            Putting: 3
                            Getting: 3
                            Putting: 4
                            Getting: 4
                            Putting: 5
                            Getting: 5