// import java.util.Random;
import java.util.concurrent.CountDownLatch;
import java.util.concurrent.locks.Condition;
import java.util.concurrent.locks.Lock;
import java.util.concurrent.locks.ReentrantLock;
class TacoTruck {
public static final int TOTAL_TACOS = 50;
public static final int NR_CUSTOMERS = 25;
public static final int MAX_TACOS_ON_COUNTER = 2;
public static final int TACO_MAKING_TIME_MS = 1000;
private final Lock lock = new ReentrantLock();
private final Condition counterIsFull = lock.newCondition();
private final Condition counterIsEmpty = lock.newCondition();
private int tacosOnCounter = 0;
public void makeTaco() throws InterruptedException {
lock.lock();
try {
while (tacosOnCounter >= MAX_TACOS_ON_COUNTER) {
counterIsFull.await();
}
tacosOnCounter++;
System.out.println("Chef made a taco. Tacos on counter: " + tacosOnCounter);
counterIsEmpty.signalAll();
} finally {
lock.unlock();
}
}
public void consumeTaco(int customerID) throws InterruptedException {
lock.lock();
try {
while (tacosOnCounter == 0) {
counterIsEmpty.await();
}
tacosOnCounter--;
System.out.println("Customer " + customerID + " consumed a taco. Tacos left on counter: " + tacosOnCounter);
counterIsFull.signalAll();
} finally {
lock.unlock();
}
}
}
class Chef implements Runnable {
private final TacoTruck tacoTruck;
public Chef(TacoTruck tacoTruck) {
this.tacoTruck = tacoTruck;
}
@Override
public void run() {
try {
for (int i = 0; i < TacoTruck.TOTAL_TACOS; i++) {
Thread.sleep(TacoTruck.TACO_MAKING_TIME_MS);
tacoTruck.makeTaco();
}
} catch (InterruptedException e) {
Thread.currentThread().interrupt();
System.err.println("Chef was interrupted and stops making tacos.");
}
}
}
class Customer implements Runnable {
private final TacoTruck tacoTruck;
private final int customerID;
private final CountDownLatch latch;
public Customer(TacoTruck tacoTruck, int customerID, CountDownLatch latch) {
this.tacoTruck = tacoTruck;
this.customerID = customerID;
this.latch = latch;
}
@Override
public void run() {
try {
Thread.sleep(3000 + customerID*1000);
tacoTruck.consumeTaco(customerID);
} catch (InterruptedException e) {
Thread.currentThread().interrupt();
System.err.println("Customer " + customerID + " was interrupted before consuming a taco.");
} finally {
latch.countDown();
}
}
}
public class KjorTacoTruck {
public static void main(String[] args) {
TacoTruck tacoTruck = new TacoTruck();
CountDownLatch customerLatch = new CountDownLatch(TacoTruck.NR_CUSTOMERS);
Thread chefThread1 = new Thread(new Chef(tacoTruck));
Thread chefThread2 = new Thread(new Chef(tacoTruck));
Thread[] customerThreads = new Thread[TacoTruck.NR_CUSTOMERS];
for (int i = 0; i < TacoTruck.NR_CUSTOMERS; i++) {
customerThreads[i] = new Thread(new Customer(tacoTruck, i + 1, customerLatch));
}
chefThread1.start();
for (Thread customerThread : customerThreads) {
customerThread.start();
}
try {
customerLatch.await();
chefThread1.interrupt(); chefThread2.interrupt();
} catch (InterruptedException e) {
System.err.println("The main thread was interrupted while waiting for the customers. Program exits.");
System.exit(1);
}
System.out.println("All customers are served. The foodtruck is closing!");
}
}