package com.tom; import java.util.LinkedList; import java.util.Queue; import java.util.concurrent.ThreadLocalRandom; import java.util.concurrent.locks.Condition; import java.util.concurrent.locks.Lock; import java.util.concurrent.locks.ReentrantLock; class Plate<T> { private final Lock lock = new ReentrantLock(); private final Condition PLATE_NOT_FULL = lock.newCondition(); private final Condition PLATE_NOT_EMPTY = lock.newCondition(); private final Queue<T> plates = new LinkedList<T>(); private int size; public Plate(int size) { this.size = size; } public void produce(T fruit) { lock.lock(); try { if (plates.size() >= size) { try { System.out.println(Thread.currentThread().getName() + ", The plate is full..waiting to put into the plate"); PLATE_NOT_FULL.await(); } catch (InterruptedException e) { e.printStackTrace(); } } System.out.println(Thread.currentThread().getName() + ", The plate is not full..put the fruit into the plate: " + fruit); plates.offer(fruit); PLATE_NOT_EMPTY.signalAll(); } finally { if (lock != null){ lock.unlock(); } } } public T consume() { T fruit = null; lock.lock(); try { if (plates.isEmpty()) { try { System.out.println(Thread.currentThread().getName() + ", The plate is empty..waiting to consume"); PLATE_NOT_EMPTY.await(); } catch (InterruptedException e) { e.printStackTrace(); } } fruit = plates.poll(); System.out.println(Thread.currentThread().getName() + ",The plate is not empty, consume the fruit: " + fruit); PLATE_NOT_FULL.signalAll(); } finally { if (lock != null){ lock.unlock(); } } return fruit; } } public class ThreadCommunication { private static volatile boolean shutdown = false; public static void main(String[] args) { final Plate<Integer> plate = new Plate<Integer>(8); Thread[] consumers = new Thread[3]; for (int i = 0; i < consumers.length; i++) { consumers[i] = new Thread() { @Override public void run() { while (!shutdown) { plate.consume(); try { Thread.sleep(200); } catch (InterruptedException e) { e.printStackTrace(); } } } }; consumers[i].start(); } Thread[] producers = new Thread[2]; for (int i = 0; i < producers.length; i++) { producers[i] = new Thread() { @Override public void run() { while (!shutdown) { plate.produce(ThreadLocalRandom.current().nextInt(100, 1000)); try { Thread.sleep(100); } catch (InterruptedException e) { e.printStackTrace(); } } } }; producers[i].start(); } try { Thread.sleep(6000); shutdown = true; } catch (InterruptedException e) { e.printStackTrace(); } } }