Advertisement
Not a member of Pastebin yet?
Sign Up,
it unlocks many cool features!
- /*
- * To change this license header, choose License Headers in Project Properties.
- * To change this template file, choose Tools | Templates
- * and open the template in the editor.
- */
- package test;
- /*
- * This file contains the main function which is called on execution and is
- * used to start up all the relevant threads in order to complete the
- * simulation. The main function takes 3 parameters as input through command
- * line: nWorkers, nBuyers and sTime, in that order.
- */
- import java.util.Random;
- import java.util.concurrent.Semaphore;
- import java.util.concurrent.locks.ReentrantLock;
- public class Test {
- /*
- * Integer used to store the number of worker threads.
- */
- private static int nWorkers = 5;
- /*
- * Integer used to store the number of buyer threads.
- * CHANGE THIS TO 5 AND THE PROGRAM RUNS FINE!
- */
- private static int nBuyers = 5;
- /*
- * Integer used to store the interval at which the ResourceSupplier supplies
- * the warehouse with resources.
- */
- private static int sTime = 1000;
- /*
- * An array of buyer threads used to simulate buyers
- * of the warehouse.
- */
- private static Buyer[] buyers;
- /*
- * An array of DispatchWorkers threads used to simulate workers in
- * the warehouse.
- */
- private static DispatchWorker[] workers;
- /*
- * A ResourceSupplier thread used to simulate a resource supplier for
- * the warehouse.
- */
- private static ResourceSupplier supplier;
- /*
- * A warehouse object acting as common object for all threads to communicate
- * through and interract with each other.
- */
- private static Warehouse warehouse;
- /*
- * A Random variable used to generate random values.
- */
- private static Random rand;
- /*
- * This function is used to initiate all other threads and start them all.
- */
- public static void main(String[] args) {
- //A boolean used to store if a buyer is prime or not.
- boolean isPrime;
- //Integer used to count the number of prime buyers.
- int iPrime = 0;
- //Long used to store total waiting time of all prime buyers.
- long timePrime = 0;
- //Long used to store total waiting time of all normal buyers.
- long timeNormal = 0;
- //Instantiate the random variable.
- rand = new Random();
- //Check if the amount of arguments given is correct.
- //The program can start it's main execution.
- //Instantiate a new warehouse.
- warehouse = new Warehouse();
- //Instantiate the workers and buyers array.
- workers = new DispatchWorker[nWorkers];
- buyers = new Buyer[nBuyers];
- //Instantiate the ResourceSupplier thread.
- supplier = new ResourceSupplier(warehouse,
- "ResourceSupplier",
- sTime);
- //Start the ResourceSupplier thread.
- supplier.start();
- //Enumerate through all buyer threads. we can't use:
- //for (Buyer buyer : buyers) as that would not assign to the
- //array but to the temporary variable.
- for (int j = 0; j < buyers.length; j++) {
- //Generate a random value and, if bigger than 3, assign
- //true to isPrime, false otherwise.
- isPrime = (rand.nextInt(10) + 1 > 3);
- //Instantiate a new buyer thread in the jth cell of the
- //array with name equal to buyer(j + 1) to counter the fact
- //that arays start at 0.
- buyers[j] = new Buyer(warehouse,
- isPrime,
- "buyer" + (j + 1));
- //Start the buyer thread.
- buyers[j].start();
- //Notify the user that a new buyer thread has been started.
- System.out.println("started buyer: " + (j + 1));
- }
- //Enumerate through all worker threads. we can't use:
- //for (Worker worker : workers) as that would not assign to the
- //array but to the temporary variable.
- for (int j = 0; j < workers.length; j++) {
- //Instantiate a new worker thread in the jth cell of the
- //array with name equal to worker(j + 1) to counter the fact
- //that arays start at 0.
- workers[j] = new DispatchWorker(warehouse,
- "worker" + (j + 1));
- //Start the worker thread.
- workers[j].start();
- //Notify the user that the worker thread has started.
- System.out.println("started worker: " + (j + 1));
- }
- //All threads are running.
- try{
- //Notify the user that we are waiting on the users to
- //finish.
- System.out.println("Joining buyers. ");
- //Enumerate through all buyers.
- for (Buyer buyer : buyers) {
- //Wait untill the buyer thread is finished executing.
- buyer.join();
- //Notify the user a thread has finished execution.
- System.out.println("Joining thread: " +
- buyer.getName());
- //Display the avarage time for the buyer.
- System.out.println("Buyer: " + buyer.getName() +
- " took on avarage: " +
- buyer.avarageTime() +
- "ms. ");
- //Check if the buyer is prime
- if(buyer.isPrime()){
- //Add the waiting time to the total waiting time of
- //prime buyers
- timePrime += buyer.avarageTime();
- //increase the number of prime buyers.
- iPrime++;
- } else
- //add the waiting time to the total waiting time of
- //normal buyers.
- timeNormal += buyer.avarageTime();
- }
- //All packs have been delivered. Notify the user of this
- //fact.
- System.out.println("All Packs Delivered.");
- //Enumerate through all workers.
- for (DispatchWorker worker : workers) {
- //Notify the thread it should terminate it's main loop.
- worker.runThread(false);
- //Interrupt the thread so that it returns to evaluating
- //if it should run the main loop again.
- worker.interrupt();
- //The thread wil now finish and we can wait for it.
- worker.join();
- }
- //Notify the supplier to stop it's main loop. We don't have
- //to interrupt this thread as there is no manner in which it
- //can get stuck and not return to the main loop evaluation
- //after a small amount of time.
- supplier.runThread(false);
- //Wait for the supplier thread to finish.
- supplier.join();
- //Notify the user of the fact all threads have finished
- //execution.
- System.out.println("All threads finished. ");
- //Show the avarage waiting times for prime buyers
- System.out.println("The avarage waiting time "
- + "for prime buyers is"
- + timePrime / iPrime
- + "ms. ");
- //Show the avarage waiting times for normal buyers. The
- //number of normal buyers is calculated by subtracting the
- //number of prime buyers of the total number of buyers.
- System.out.println("The avarage waiting time "
- + "for normal buyers is "
- + timeNormal / (nBuyers - iPrime)
- + "ms. ");
- //Catch any interruptExceptions which may happen.
- } catch(InterruptedException e){
- //Print the stackTrace to show where the InterruptException
- //happend. During normal execution this should not happen.
- //Therefor we want to show where the InterruptException
- //Came from and what triggered this behavior.
- e.printStackTrace();
- }
- //Notify the user that the program has finished execution.
- System.out.println("Simulation finished. ");
- }
- public static class Order {
- /*
- * An integer used to store the number of packages to order.
- */
- private int nPacks;
- /*
- * Buyer refrence used to store the buyer who made the order.
- */
- private Buyer buyer;
- /*
- * Boolean used to store if the order is prime or not.
- */
- private boolean prime;
- /*
- * Long used to store the time at which the order was placed.
- */
- private long orderTime;
- /*
- * Constructor for the order class.
- */
- public Order(int nPacks, Buyer buyer, boolean prime) {
- this.nPacks = nPacks;
- this.buyer = buyer;
- this.prime = prime;
- }
- /*
- * Obtain the number of packages in the order.
- */
- public int getnPacks() {
- return nPacks;
- }
- /*
- * Set the number of packages in the order.
- */
- public void setnPacks(int nPacks) {
- this.nPacks = nPacks;
- }
- /*
- * Obtain the buyer who made the order.
- */
- public Buyer getBuyer() {
- return buyer;
- }
- /*
- * Set the buyer who made the order.
- */
- public void setBuyer(Buyer buyer) {
- this.buyer = buyer;
- }
- /*
- * Obtain if this order is prime.
- */
- public boolean isPrime() {
- return prime;
- }
- /*
- * Set if this order is prime.
- */
- public void setPrime(boolean prime) {
- this.prime = prime;
- }
- /*
- * Get the time at which the order was placed.
- */
- public long getOrderTime() {
- return orderTime;
- }
- /*
- * Set the time at which the order was placed.
- */
- public void setOrderTime(long orderTime) {
- this.orderTime = orderTime;
- }
- }
- public static class Buyer extends Thread{
- /*
- * Integer variable used to store the amount of packages bought.
- */
- private int packsBought = 0;
- /*
- * Boolean used to store if the buyer makes used of prime service.
- */
- private boolean isPrime;
- /*
- * A random variable used to generate random numbers.
- */
- private Random rand;
- /*
- * A refrence to warehouse used to communicate with the other threads.
- */
- private Warehouse warehouse;
- /*
- * Long used to store the time the buyer has been waiting for all orders
- * consecutively.
- */
- private long waitingTime = 0;
- /*
- * The constructor of the buyer class.
- */
- public Buyer(Warehouse warehouse, Boolean isPrime, String name) {
- super(name);
- this.isPrime = isPrime;
- this.rand = new Random();
- this.warehouse = warehouse;
- }
- /*
- * The run method which is ran once the thread is started.
- */
- public void run() {
- //Run until the thread has bought 10 packages, this ensures the thread
- //will eventually stop execution automatically.
- for(packsBought = 0; packsBought < 10; packsBought++)
- {
- try {
- //Sleep for a random amount of time between 1 and 50
- //milliseconds.
- Thread.sleep(this.rand.nextInt(49) + 1);
- //Catch any interruptExceptions.
- } catch (InterruptedException ex) {
- //There is no problem if this exception is thrown, the thread
- //will just make an order earlier than planned. that being said
- //there should be no manner in which this exception is thrown.
- }
- //Create a new order.
- Order order = new Order(this.rand.nextInt(3)+ 1,
- this,
- this.isPrime);
- //Set the time at which the order was placed as now.
- order.setOrderTime(System.currentTimeMillis());
- //place the newly created order in the warehouse.
- this.warehouse.placeOrder(order);
- }
- //Notify the thread has finished execution.
- System.out.println("Thread: " + super.getName() + " has finished.");
- }
- /*
- * Returns the avarage time the buyer needed to get his orders.
- */
- public long avarageTime()
- {
- return this.waitingTime / this.packsBought;
- }
- /*
- * Check if the thread makes use of the prime service.
- */
- public boolean isPrime() {
- return this.isPrime;
- }
- /*
- * Get the total waiting time of this buyer
- */
- public long getWaitingTime() {
- return waitingTime;
- }
- /*
- * Set the total waiting time of this buyer
- */
- public void setWaitingTime(long waitingTime) {
- this.waitingTime = waitingTime;
- }
- }
- public static class Warehouse {
- /*
- * An array used to store the list of orders to process.
- */
- private Order[] buffer;
- /*
- * Lock used to garantee mutial exclusion of buffer,
- */
- private ReentrantLock mutexBuffer;
- /*
- * Semaphore used to suspend the DispatchWorkers if the warehouse if full
- * of packs.
- */
- private Semaphore notFullBuffer;
- /*
- * Semaphore use dto suspend the Buyers if the warehouse is empty.
- */
- private Semaphore notEmptyBuffer;
- /*
- * Semaphore used to notify the workers of how many boxes are available.
- */
- private Semaphore hasBoxes;
- /*
- * Semaphore used to notify the workers of how much tape is available.
- */
- private Semaphore hasTape;
- /*
- * Define the size of the warehouse (the maximum number of packs the
- * warehouse is able to store).
- */
- private int sizeOrderList = 100;
- /*
- * Counter used to keep track of the position to insert normal orders
- * into the buffer array.
- */
- private int inNormal = 0;
- /*
- * Counter used to keep track of the position to insert prime orders
- * into the buffer array.
- */
- private int inPrime = 0;
- /*
- * Constructure for the Warehouse class.
- */
- public Warehouse() {
- //Instantiate the array used to store orders based on the predifined
- //buffer size.
- buffer = new Order[sizeOrderList];
- //Initialize the lock
- this.mutexBuffer = new ReentrantLock();
- //Initialize the semaphore used to suspend the DispatchWorkers to the
- //size of the warehouse such that we assume the warehouse to be empty
- //when the simulation starts. (all packs can be made)
- this.notFullBuffer = new Semaphore(sizeOrderList);
- //Initialize the semaphore used to suspend the Buyers to the
- //0 of the warehouse such that we assume the warehouse to be empty
- //when the simulation starts. (no packs can be bought)
- this.notEmptyBuffer = new Semaphore(0);
- //Instantiate the semaphore used to keep track of the number of boxes
- //available in the warehouse. We assume that at the start of the
- //simulation no boxes are present.
- this.hasBoxes = new Semaphore(0);
- //Instantiate the semaphore used to keep track of the amount of tape
- //available in the warehouse. We assume that at the start of the
- //simulation no tape is present.
- this.hasTape = new Semaphore(0);
- }
- /*
- * Given an order in input, we add the order to the buffer list such that
- * all prime orders are at the start of the list and the non prime orders
- * are behind that. both in FIFO order.
- */
- public void placeOrder(Order order) {
- try{
- //halt untill there are enough packs to handle an order.
- this.notFullBuffer.acquire();
- //Lock to signify the start of the critical section.
- this.mutexBuffer.lock();
- //Insert the order in the buffer depending on prime status.
- if (order.isPrime()) {
- //prime order, insert behind all prime orders in buffer.
- //Enumerate all non prime orders in the list.
- for (int i = inPrime; i < sizeOrderList - 1; i++) {
- //Move the non prime order back 1 position in the list.
- buffer[i + 1] = buffer[i];
- }
- // Insert the prime order.
- buffer[inPrime++] = order;
- } else {
- //No prime order, insert behind all orders in buffer.
- buffer[inPrime + inNormal++] = order;
- }
- //Notify the DispatchWorkers that a new order has been placed.
- this.notEmptyBuffer.release();
- //Catch any InterruptException that might occure.
- } catch(InterruptedException e){
- //Even though this isn't expected behavior, there is no reason to
- //notify the user of this event or to preform any other action as
- //the thread will just return to the queue before placing another
- //error if it is still required to do so.
- } finally {
- //Unlock and finalize the critical section.
- mutexBuffer.unlock();
- }
- }
- /*
- * Handle a single order from the buffer.
- */
- public void handleOrder(){
- //Create a variable to store the order being handled.
- Order toHandle = null;
- try{
- //wait until there is an order to handle.
- this.notEmptyBuffer.acquire();
- //Lock to signify the start of the critical section.
- this.mutexBuffer.lock();
- //obtain the first order to handle as the first element of the buffer
- toHandle = buffer[0];
- //move all buffer elementst back by 1 position.
- for(int i = 1; i < sizeOrderList; i++){
- buffer[i - 1] = buffer[i];
- }
- //set the last element in the buffer to null
- buffer[sizeOrderList - 1] = null;
- //We have obtained an order from the buffer and now we can handle it.
- if(toHandle != null) {
- int nPacks = toHandle.getnPacks();
- //wait until the appropriate resources are available.
- this.hasBoxes.acquire(nPacks);
- this.hasTape.acquire(nPacks * 50);
- //Now we can handle the order (Simulated by sleeping. Although
- //in real live Amazon workers also have about 5ms of time per
- //package).
- Thread.sleep(5 * nPacks);
- //Calculate the total time this order took.
- long time = System.currentTimeMillis() -
- toHandle.getOrderTime();
- //Update the total waiting time for the buyer.
- toHandle.getBuyer().setWaitingTime(time +
- toHandle.getBuyer().getWaitingTime());
- //Check if the order to handle is prime or not.
- if(toHandle.isPrime()) {
- //Decrement the position of which prime orders are
- //inserted into the buffer.
- inPrime--;
- } else {
- //Decrement the position of which normal orders are
- //inserted into the buffer.
- inNormal--;
- }
- //Print a message informing the user a new order was completed.
- System.out.println("An order has been completed for: "
- + toHandle.getBuyer().getName());
- }else {
- //Notify the user there was a critical error obtaining the
- //error to handle. (There shouldn't exist a case where this
- //should happen but you never know.)
- System.err.println("Something went wrong obtaining an order.");
- }
- //Notify the buyers that a new spot has been opened in the buffer.
- this.notFullBuffer.release();
- //Catch any interrupt exceptions.
- } catch(InterruptedException e){
- //This is expected behavior as it allows us to force the thread to
- //revaluate it's main running loop when notifying it to finish
- //execution.
- } finally {
- //Check if the current thread is locking the buffer lock. This is
- //done as in the case of an interrupt we don't want to execute this
- //code if the thread interrupted doesn't hold the lock as that
- //would result in an exception we don't want.
- if (mutexBuffer.isHeldByCurrentThread())
- //Unlock the buffer lock.
- mutexBuffer.unlock();
- }
- }
- /*
- * Deposit nBoxes number of boxes and nTape cm of tape in the warehouse
- * to be used by the workers.
- */
- public void depositResources(int nBoxes, int nTape) {
- //Notify the workers of the amount of materials which the
- //ResourceSupplier has supplied.
- this.hasBoxes.release(nBoxes);
- this.hasTape.release(nTape);
- }
- }
- public static class ResourceSupplier extends Thread{
- /*
- * A random variable used to generate random numbers.
- */
- private Random rand;
- /*
- * An integer variable used to store how long the thread should wait
- * between proviing resources to the warehouse, measured in tmilliseconds.
- */
- private int sTime;
- /*
- * A refrence to warehouse used to communicate with the other threads.
- */
- private Warehouse warehouse;
- /*
- * A boolean used to indicate the thread should run another cycle or not.
- */
- private boolean run = true;
- /*
- * The constructor of the ResourceSupplier class.
- */
- public ResourceSupplier(Warehouse warehouse, String name, int sTime) {
- super(name);
- this.warehouse = warehouse;
- this.sTime = sTime;
- this.rand = new Random();
- }
- /*
- * The run method which is ran once the thread is started.
- */
- public void run() {
- //Run until notified not to.
- while(run){
- //Deposit resources in the warehouse.
- this.warehouse.depositResources(this.rand.nextInt(100),
- this.rand.nextInt(5000));
- try {
- //Wait for the amount of time spesified by sTime.
- Thread.sleep(this.sTime);
- } catch (InterruptedException ex) {
- //Notify the user the thread was interrupted while sleeping.
- System.out.println("Resource Supplier Interrupted. ");
- //Make sure run is false as we don't want to run another cycle.
- run = false;
- }
- }
- }
- /*
- * A function used to indicate a thread should run another cycle or not.
- */
- public void runThread(Boolean run){
- this.run = run;
- }
- }
- public static class DispatchWorker extends Thread{
- /*
- * A refrence to warehouse used to communicate with the other threads.
- */
- private Warehouse warehouse;
- /*
- * A boolean used to indicate the thread should run another cycle or not.
- */
- private boolean run = true;
- /*
- * Constructor for the DispatchWorker class.
- */
- public DispatchWorker(Warehouse warehouse, String name) {
- super(name);
- this.warehouse = warehouse;
- }
- /*
- * The run method which is ran once the thread is started.
- */
- public void run() {
- //Run until told not to.
- while(run){
- //Handle an error.
- warehouse.handleOrder();
- }
- }
- /*
- * A function used to indicate a thread should run another cycle or not.
- */
- public void runThread(Boolean run){
- this.run = run;
- }
- }
- }
Advertisement
Add Comment
Please, Sign In to add comment
Advertisement