import java.util.Random; import java.util.concurrent.BlockingQueue; import java.util.concurrent.LinkedBlockingQueue; public class ChapattiStore { // Simple builder class for the store public static class Builder { private boolean verbose; private int chappatiToMake; private int bakers; private int bakeMeanTime; private int bakeStdDeviation; private int makers; private int makeMeanTime; private int makeStdDeviation; private int packageMeanTime; private int packageStdDeviation; public Builder verbose(boolean verbose) { this.verbose = verbose; return this; } public Builder chappatiToMake(int chappatiToMake) { this.chappatiToMake = chappatiToMake; return this; } public Builder bakers(int bakers) { this.bakers = bakers; return this; } public Builder bakeMeanTime(int bakeMeanTime) { this.bakeMeanTime = bakeMeanTime; return this; } public Builder bakeStdDeviation(int bakeStdDeviation) { this.bakeStdDeviation = bakeMeanTime; return this; } public Builder makers(int makers) { this.makers = makers; return this; } public Builder makeMeanTime(int makeMeanTime) { this.makeMeanTime = makeMeanTime; return this; } public Builder makeStdDeviation(int makeStdDeviation) { this.makeStdDeviation = makeStdDeviation; return this; } public Builder packageMeanTime(int packageMeanTime) { this.packageMeanTime = packageMeanTime; return this; } public Builder packageStdDeviation(int packageStdDeviation) { this.packageStdDeviation = packageStdDeviation; return this; } public ChapattiStore build() { ChapattiStore chapattiStore = new ChapattiStore(); chapattiStore.verbose = this.verbose; chapattiStore.chappatiToMake = this.chappatiToMake; chapattiStore.bakers = this.bakers; chapattiStore.bakeMeanTime = this.bakeMeanTime; chapattiStore.bakeStdDeviation = this.bakeStdDeviation; chapattiStore.makers = this.makers; chapattiStore.makeMeanTime = this.makeMeanTime; chapattiStore.makeStdDeviation = this.makeStdDeviation; chapattiStore.packageMeanTime = this.packageMeanTime; chapattiStore.packageStdDeviation = this.packageStdDeviation; return chapattiStore; } } private boolean verbose; // True for thread progress logs private int chappatiToMake; // number of chappati to make private int bakers; // number of bakers private int bakeMeanTime; // mean time to prepare dough for one chappati - in ms private int bakeStdDeviation; // standard deviation to prepare dough for one chappati - in ms private int makers; // number of chappati makers private int makeMeanTime; // mean time to make one chappati with baked dough- in ms private int makeStdDeviation; // standard deviation to make one chappati with baked dough - in ms private int packageMeanTime; // mean time to package one chapatti - in ms private int packageStdDeviation; // standard deviation top package one chapatti - in ms private BlockingQueue dough; private BlockingQueue baked; private BlockingQueue made; /* work blocks the thread invoked for a period of time that is normally distributed around mean with a standard deviation of stddev. */ private int work(int mean, int stdDeviation) throws InterruptedException { Random r = new Random(); int delay = (int) r.nextGaussian() * stdDeviation + mean; if (delay < 0) delay = mean; Thread.sleep(delay); return delay; } // Bake a chappati and send it to the baked queue. private void baker() throws InterruptedException { // Take dough var d = dough.take(); if (verbose) { System.out.println("baking " + d); } work(bakeMeanTime, bakeStdDeviation); // Send baked dough after work baked.put(d); } // Retrieve from the baked queue a dough and make a chappati with it. private void maker() throws InterruptedException { // Take a baked dough var bakedDough = baked.take(); if (verbose) { System.out.println("making " + bakedDough); } work(makeMeanTime, makeStdDeviation); // Send a made chapatti after work made.put(bakedDough); } // Package chapatti and sell them private void packager() throws InterruptedException { for (int i = 0; i < chappatiToMake; i++) { var chapattiReady = made.take(); if (verbose) { System.out.println("packaging " + chapattiReady); } work(packageMeanTime, packageStdDeviation); if (verbose) { System.out.println("selling " + chapattiReady); } } } public float run() throws InterruptedException { dough = new LinkedBlockingQueue<>(); baked = new LinkedBlockingQueue<>(); made = new LinkedBlockingQueue<>(); for (int i = 0; i < chappatiToMake; i++) { dough.put(i); } long startTime = System.currentTimeMillis(); for (int i = 0; i < bakers; i++) { Runnable bake = () -> { while (true) { try { baker(); } catch (InterruptedException e) { e.printStackTrace(); } } }; Thread t = new Thread(bake); t.start(); } for (int i = 0; i < makers; i++) { Runnable make = () -> { while (true) { try { maker(); } catch (InterruptedException e) { e.printStackTrace(); } } }; Thread t = new Thread(make); t.start(); } packager(); return System.currentTimeMillis() - startTime; } @Override public String toString() { StringBuilder stringBuilder = new StringBuilder(); stringBuilder.append(String.format("Baking{Bakers:%d,BakeStdDev:%dms,BakeMeanTime:%dms}\n", bakers, bakeStdDeviation, bakeMeanTime)); stringBuilder.append(String.format("Making{Makers:%d,MakeStdDev:%dms,MakeMeanTime:%dms}\n", makers, makeStdDeviation, makeMeanTime)); stringBuilder.append(String.format("Packaging{PackageMeanTime:%dms,PackageStdDev:%dms}\n", packageStdDeviation, packageMeanTime)); return stringBuilder.toString(); } public static void main(String[] args) throws InterruptedException { Builder builder = new Builder(); // Change the below values - read the comments for attributes above builder.verbose(false).chappatiToMake(10) .bakers(5).bakeMeanTime(500).bakeStdDeviation(10) .makers(5).makeMeanTime(200).makeStdDeviation(10) .packageMeanTime(100).packageStdDeviation(10); ChapattiStore chapattiStore = builder.build(); System.out.printf("We closed, took %.2fs to prepare %d chappatis.\n%n", chapattiStore.run() / 1000, chapattiStore.chappatiToMake); System.out.print(chapattiStore); } }