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();
}
}
}