Skip to content

Instantly share code, notes, and snippets.

@markselby9
Created September 7, 2016 06:23
Show Gist options
  • Save markselby9/a00603b3cab0f4f042a8a8776a389d72 to your computer and use it in GitHub Desktop.
Save markselby9/a00603b3cab0f4f042a8a8776a389d72 to your computer and use it in GitHub Desktop.
Producer Consumer problem, with a buffer whose max size is 10. The chef and waiter start working with random time needed each time, so randomly the buffer would be full or empty at some time.
import java.util.ArrayList;
import java.util.Random;
import java.util.concurrent.ExecutorService;
import java.util.concurrent.Executors;
import java.util.concurrent.TimeUnit;
import static java.lang.Thread.sleep;
/**
* Created by fengchaoyi on 16/9/6.
*/
//Thinking in Java P703
public class ProducerConsumerProblemWithBuffer {
public static void main(String[] args) {
new Restaurant();
}
}
class Restaurant {
private ArrayList<Meal> mealArrayList = new ArrayList<Meal>();
private int mealBufferMaxSize = 10; // set the buffer size as 10
Waiter waiter;
Chef chef;
ExecutorService executorService = Executors.newCachedThreadPool();
Restaurant() {
this.mealArrayList = new ArrayList<Meal>();
this.waiter = new Waiter(this);
this.chef = new Chef(this);
executorService.execute(chef);
try {
sleep(100); //chef work first
} catch (InterruptedException e) {
e.printStackTrace();
}
executorService.execute(waiter);
}
boolean bufferFull() {
return mealArrayList.size() == mealBufferMaxSize;
}
boolean bufferEmpty() {
return mealArrayList.size() == 0;
}
Meal popMeal() {
return mealArrayList.remove(0);
}
void addMeal(Meal meal) {
mealArrayList.add(meal);
}
}
class Waiter implements Runnable {
private Restaurant restaurant;
Waiter(Restaurant restaurant) {
this.restaurant = restaurant;
this.restaurant.waiter = this;
}
@Override
public void run() {
try {
while (!Thread.interrupted()) {
synchronized (this) {
if (restaurant.bufferEmpty()) {
System.out.println("Buffer empty, wait for chef.");
wait(); // wait for chef's notifyAll()
}
}
Meal nextMeal = restaurant.popMeal();
TimeUnit.MILLISECONDS.sleep(new Random().nextInt(100));
nextMeal.process();
synchronized (restaurant.chef) {
restaurant.chef.notifyAll();
}
}
} catch (InterruptedException e) {
System.out.println("ProducerConsumer1.Waiter interrupted");
}
}
}
class Chef implements Runnable {
private Restaurant restaurant;
private int count;
private int materialCount = 100;
Chef(Restaurant restaurant) {
this.restaurant = restaurant;
this.restaurant.chef = this;
this.count = 0;
}
@Override
public void run() {
try {
while (!Thread.interrupted()) {
synchronized (this) {
// // this lock of chef is automatically released, so that waiter.notifyAll() can catch this lock
if (restaurant.bufferFull()) {
System.out.println("Buffer is full, wait for waiter.");
wait();
}
}
this.count += 1;
if (this.count > this.materialCount) {
System.out.println("Running out of material. Closing...");
restaurant.executorService.shutdownNow();//not shutdown()
}
Meal newMeal = new Meal(this.count);
TimeUnit.MILLISECONDS.sleep(new Random().nextInt(100));
restaurant.addMeal(newMeal);
synchronized (restaurant.waiter) {
System.out.println("notifyAll waiter for meal " + count + " ready.");
restaurant.waiter.notifyAll();
}
}
} catch (InterruptedException e) {
System.out.println("ProducerConsumer1.Chef interrupted");
}
}
}
class Meal {
private int number;
Meal(int number) {
this.number = number;
}
void process() {
System.out.println("ProducerConsumer1.Meal " + this.number + " is being given to customer!");
}
}
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment