Java Multithreading: Low-Level Producer-Consumer (Video Tutorial Part 9)

In this tutorial we'll look at how to implement the producer-consumer pattern using "low level" techniques; namely, wait, notify and synchronized. This isn't the best way to implement a producer-consumer pattern in Java (see tutorial 7 for the best way); but this tutorial will help you to understand how to use wait and notify.

After starting the video, click the maximise button to make it fullscreen so you can see the code!



Code For This Tutorial



The main program just runs the produce() and consume() methods in different threads.

 
import java.util.LinkedList;
import java.util.Random;

public class Processor {

    private LinkedList<Integer> list = new LinkedList<Integer>();
    private final int LIMIT = 10;
    private Object lock = new Object();

    public void produce() throws InterruptedException {

        int value = 0;

        while (true) {

            synchronized (lock) {
                
                while(list.size() == LIMIT) {
                    lock.wait();
                }
                
                list.add(value++);
                lock.notify();
            }

        }
    }

    public void consume() throws InterruptedException {
        
        Random random = new Random();

        while (true) {

            synchronized (lock) {
                
                while(list.size() == 0) {
                    lock.wait();
                }
                
                System.out.print("List size is: " + list.size());
                int value = list.removeFirst();
                System.out.println("; value is: " + value);
                lock.notify();
            }
            
            Thread.sleep(random.nextInt(1000));
        }
    }
}

 
List size is: 2; value is: 0
List size is: 10; value is: 1
List size is: 10; value is: 2
List size is: 10; value is: 3
List size is: 10; value is: 4
List size is: 10; value is: 5
List size is: 10; value is: 6
List size is: 10; value is: 7
List size is: 10; value is: 8





The main program (just creates and runs two threads):

 

public class App {

    public static void main(String[] args) throws InterruptedException {

        final Processor processor = new Processor();

        Thread t1 = new Thread(new Runnable() {

            @Override
            public void run() {
                try {
                    processor.produce();
                } catch (InterruptedException e) {
                    e.printStackTrace();
                }
            }
        });

        Thread t2 = new Thread(new Runnable() {

            @Override
            public void run() {
                try {
                    processor.consume();
                } catch (InterruptedException e) {
                    e.printStackTrace();
                }
            }
        });
        
        t1.start();
        t2.start();
        
        t1.join();
        t2.join();
    }
}