Handling Condtion in ThreadPoolExecutor to execute - java

I have the following Scenario.
There is a restroom in a Building.
It will have 2 types[As of now] of toilet. MALE and FEMALE which is n in number.
If a group of People enters into a restroom.I want them to occupy maximum no of rooms as possible.
Assume there are 20 people entering into restroom at a time with the following combination
People 20
Male 10 Female 10
RestRoom Avaialbiltiy
MALE 2
FEMALE 1
And some people will take more time, so the next person have to wait in the queue.And male cannot enter into female toilet and vice-versa.
For the above scenario I have extended the ThreadpoolExecutor and add the Person one by one and check assign them as soon as toilet with match is avaialable.
So here is the MCVE for the example.I wanted to check if this is the correct way to handle condition in a ThreadPool
RestRoom.java
import java.util.HashMap;
import java.util.Map;
public enum RestRoom {
MALE,
FEMALE;//will extend for ex [Differently Abled]
public int maxInstance = 0;
public RestRoom withMaxInstance(int maxInstance) {
this.maxInstance = maxInstance;
return this;
}
public static int getTotalNoOfRestRooms() {
int count = 0;
for (RestRoom room : RestRoom.values()) {
count += room.maxInstance;
}
return count;
}
public static Map<RestRoom, Integer> getAvailabiltyAsMap() {
Map<RestRoom, Integer> avaialbilty = new HashMap<>();
for (RestRoom room : RestRoom.values()) {
avaialbilty.put(room, room.maxInstance);
}
return avaialbilty;
}
}
Person.java (Runnable)
import java.util.logging.Level;
import java.util.logging.Logger;
public class Person implements Runnable {
private final String name;
private final RestRoom gender;
private int second;
public Person(String name, RestRoom gender) {
this.name = name;
this.gender = gender;
}
public Person withTime(int second) {
this.second = second;
return this;
}
#Override
public void run() {
try {
System.out.println("Running " + name + " with " + gender);
Thread.sleep(second * 1000);
} catch (InterruptedException ex) {
Logger.getLogger(Person.class.getName()).log(Level.SEVERE, null, ex);
}
}
public String getName() {
return name;
}
public RestRoom getGender() {
return gender;
}
#Override
public String toString() {
return "Person{" + "name=" + name + ", gender=" + gender + '}';
}
}
CustomThreadPool.java
import java.util.HashMap;
import java.util.Map;
import java.util.concurrent.LinkedBlockingDeque;
import java.util.concurrent.ThreadPoolExecutor;
import java.util.concurrent.TimeUnit;
public class CustomThreadPool extends ThreadPoolExecutor {
Map<RestRoom, Integer> avaialbilty = new HashMap<>();
LinkedBlockingDeque<Runnable> remaining = new LinkedBlockingDeque<>();
public CustomThreadPool(int corePoolSize, long keepAliveTime) {
super(corePoolSize, corePoolSize, keepAliveTime, TimeUnit.MINUTES, new LinkedBlockingDeque<Runnable>());
avaialbilty = RestRoom.getAvailabiltyAsMap();
}
#Override
protected void afterExecute(Runnable runnable, Throwable throwable) {
avaialbilty.put(getRestRoomFor(runnable), avaialbilty.get(getRestRoomFor(runnable)) + 1);
for (int i = 0; i < remaining.size(); i++) {
execute(remaining.remove());
}
if (remaining.isEmpty()) {
shutdown();
}
}
#Override
public void execute(Runnable runnable) {
if (avaialbilty.get(getRestRoomFor(runnable)) > 0) {
avaialbilty.put(getRestRoomFor(runnable), avaialbilty.get(getRestRoomFor(runnable)) - 1);
super.execute(runnable);
} else {
remaining.add(runnable);
}
}
private RestRoom getRestRoomFor(Runnable runnable) {
return asPerson(runnable).getGender();
}
private Person asPerson(Runnable runnable) {
return (Person) runnable;
}
}
Test.java
public class Test {
public static void main(String[] args) {
RestRoom.MALE.withMaxInstance(3);
RestRoom.FEMALE.withMaxInstance(2);
CustomThreadPool threadPool = new CustomThreadPool(RestRoom.getTotalNoOfRestRooms(), 2);
for (int i = 0; i < 10; i++) {
threadPool.execute(new Person("M" + i, RestRoom.MALE).withTime(2));
threadPool.execute(new Person("F" + i, RestRoom.FEMALE).withTime(1));
}
}
}

Related

Exception in thread error when running Interface

I have written a code in which I have made an interface and a class that implements that interface. Now when I run the code, i give my self 2 options i.e. 1 to Enter string and 2 to quit. Now when i run the code, if i select 1, it lets me put in string, but after this when i press 0, it gives me error: Exception in thread "main" java.lang. Can some body please help me figure out what I am missing here. Below is the code:
import java.util.ArrayList;
import java.util.List;
public interface ITimsSaveable {
List<String> write(); // this will save the data;
void read (List<String> savedValues); //this will print the data
}
import java.util.ArrayList;
import java.util.List;
public class TimsPlayers implements ITimsSaveable {
private String name;
private int hitPoints;
private int strength;
private String weapon;
public TimsPlayers(String name, int hitPoints, int strength) {
this.name = name;
this.hitPoints = hitPoints;
this.strength = strength;
this.weapon = "Sword";
}
public String getName() {
return name;
}
public void setName(String name) {
this.name = name;
}
public int getHitPoints() {
return hitPoints;
}
public void setHitPoints(int hitPoints) {
this.hitPoints = hitPoints;
}
public int getStrength() {
return strength;
}
public void setStrength(int strength) {
this.strength = strength;
}
public String getWeapon() {
return weapon;
}
public void setWeapon(String weapon) {
this.weapon = weapon;
}
//now go to generate > to string method
#Override
public String toString() {
return "TimsPlayers{" +
"name='" + name + '\'' +
", hitPoints=" + hitPoints +
", strength=" + strength +
", weapon='" + weapon + '\'' +
'}';
}
//now let us create stubs, i.e. the empty methods from interface
#Override
public List<String> write() {
List<String > values = new ArrayList<String >();
values.add(0,this.name);
values.add(1,""+this.hitPoints); //"" is quick trick to convert int to String
values.add(2,""+this.strength);
values.add(3,this.weapon);
return values;
}
#Override
public void read(List<String> savedValues) {
if ((savedValues != null) && (savedValues.size() > 0)) {
this.name = savedValues.get(0);
this.hitPoints = Integer.parseInt(savedValues.get(1));
this.strength = Integer.parseInt(savedValues.get(2));
this.weapon = savedValues.get(3);
}
// now let us go back to our main class
}
}
public class Main {
public static void main(String[] args) {
TimsPlayers tim = new TimsPlayers("Tim",10,15);
System.out.println(tim.toString());
saveObject(tim);
tim.setHitPoints(8);
System.out.println(tim);
tim.setWeapon("Stormbringer");
saveObject(tim);
loadObject(tim);
System.out.println(tim);
}
public static ArrayList<String> readValues() {
ArrayList<String> values = new ArrayList<String>();
Scanner scanner = new Scanner(System.in);
boolean quit = false;
int index = 0;
System.out.println("Choose\n" +
"1 to enter a string\n" +
"0 to quit");
while (!quit) {
System.out.print("Choose an option: ");
int choice = scanner.nextInt();
scanner.nextLine();
switch (choice) {
case 0:
quit = true;
break;
case 1:
System.out.print("Enter a string: ");
String stringInput = scanner.nextLine();
values.add(index, stringInput);
index++;
break;
}
}
return values;
}
public static void saveObject(ITimsSaveable objectToSave) { //ITims is the interface that is being implemented by the player
//class,so we can use ITims as object type
for (int i = 0; i < objectToSave.write().size(); i++) {
System.out.println("Saving " + objectToSave.write().get(i) + " to storage device");
}
}
public static void loadObject (ITimsSaveable objectToLoad) {
ArrayList<String > values = readValues();
objectToLoad.read(values);
}
}
Stacktrace:
Exception in thread "main" java.lang.IndexOutOfBoundsException: Index 1 out of bounds for length 1
at java.base/jdk.internal.util.Preconditions.outOfBounds(Preconditions.java:64)
at java.base/jdk.internal.util.Preconditions.outOfBoundsCheckIndex(Preconditions.java:70)
at java.base/jdk.internal.util.Preconditions.checkIndex(Preconditions.java:248)
at java.base/java.util.Objects.checkIndex(Objects.java:373)
at java.base/java.util.ArrayList.get(ArrayList.java:427)
at org.mm.sandbox.so.TimsPlayers.read(TimsPlayers.java:77)
at org.mm.sandbox.so.Main.loadObject(Main.java:62)
at org.mm.sandbox.so.Main.main(Main.java:17)
This method
#Override
public void read(List<String> savedValues) {
if ((savedValues != null) && (savedValues.size() > 0)) {
this.name = savedValues.get(0);
this.hitPoints = Integer.parseInt(savedValues.get(1));
this.strength = Integer.parseInt(savedValues.get(2));
this.weapon = savedValues.get(3);
}
// now let us go back to our main class
}
expects the savedValues to be completely filled, i.e. having 4 elements - name, HP, strength and weapon. You do savedValues.size() > 0 but that doesn't mean you didn't just input one of the required and then stopped and it still tries to access an element which does not exist - this.hitPoints = Integer.parseInt(savedValues.get(1));

Summing up an ArrayList with multiple types

I am having trouble summing up my ArrayList that I made in my class Treasureroom which is in my class Accountant. I have an ArrayList with type Valuable as you can see in the code below. I need to be able to sum up all the int elements from within the Accountant class.
Accountant
package Accountant;
import java.util.Iterator;
import java.util.Random;
import ValuableFactory.Valuable;
import rw.RWMonitor;
import rw.Treasureroom;
public class Accountant implements Runnable {
private Treasureroom treasureroom;
private static final int MAX_WAIT_TIME = 10000; // 3 seconds
private static final int MAX_WORK_TIME = 5000; // 2 seconds
private static final Random random = new Random();
private int no;
private RWMonitor monitor;
private Treasureroom resource;
public Accountant( int no, RWMonitor monitor, Treasureroom resource ) {
this.no = no;
this.monitor = monitor;
this.resource = resource;
}
public void run() {
while(true) {
try {
Thread.sleep(random.nextInt(WAIT_TIME));
}
catch (InterruptedException ex) {
}
System.out.println("Accountant counts: " + resource);
monitor.acquireRead();
//System.out.println("Accountant counted: " + valuable);
try {
Thread.sleep(random.nextInt(MAX_WAIT_TIME));
}
catch (InterruptedException ex) {
}
for (int i = 0; i > resource.)
System.out.println("Accountant counted: " + resource.getValueRead());
monitor.releaseRead();
try {
Thread.sleep(random.nextInt(WAIT_AGAIN));
}
catch (InterruptedException ex) {
// TODO: handle exception
}
}
}
//System.out.println("The total sum of TreasureRoom is " + Thread.currentThread().getName());
//TreasureRoom.releaseRead();
}
Treasureroom
package rw;
import java.util.*;
import ValuableFactory.*;
public class Treasureroom {
ArrayList<Valuable> valuables = new ArrayList<Valuable>();
public Valuable getValueWriter() {
return valuables.remove(0);
}
public void updateValue(Valuable valuable) {
valuables.add(valuable);
}
public boolean removeValue(Valuable valuable) {
return valuables.remove(valuable);
}
public Valuable getValueReade() {
for (int i=0; i<valuables.size();i++) {
return valuables.get(i);
}
return null;
}
}
Valuable
package ValuableFactory;
public class Valuable implements ValuableFactory {
private String name;
private int value;
public Valuable(String name, int value) {
this.name = name;
this.value = value;
}
#Override
public String getName() {
return name;
}
#Override
public int getValue() {
return value;
}
}
Your Accountant class instantiates your Treasureroom object in its constructor, meaning that to loop through the ArrayList inside the Treasureroom object using an Accountant object you would need a method in Accountant that calls a method in Treasureroom.
Accountant
public int getTreasureSum()
{
return resource.sumTreasure();
}
Treasureroom
public int sumTreasure()
{
int sum = 0;
for(int i = 0; i < valuables.size(); i++)
{
sum+= valuables.get(i).getValue();
}
return sum;
}
Also in your Accountant class you have an unused Treasureroom object
private Treasureroom treasureroom;

How can I implement the count 60 seonds for hospital

Who can help me to implement the function if the patient waiting for over 60 seconds the category will change from "low" to "high" and queue behind the newest patient category with "high". Can someone help to me to solve it?
EmergencyRoomSimulator1.java :
package emergencyroomsimulator1;
import java.util.Random;
public class EmergencyRoomSimulator1 {
private static final int WAIT_LIMIT = 1000; // 1000 = 1 second
private PatientQueue pq = new PatientQueue();
private void t() {
try { Thread.sleep(new Random().nextInt(WAIT_LIMIT));
} catch (InterruptedException e) {
}
} // end t method
private void patientArrives(Patient p) {
pq.registerPatient(p);
System.out.println(" ARRIVAL: " + p.getID());
System.out.println(" time arrived: " + p.getTimeArrived());
System.out.println(" category: " + p.getCategory());
System.out.println("------------------------------------");
t();
} // end patientArrives method
public void doctorVisits() {
Patient p = pq.getNextPatient();
System.out.println(" VISIT: " + p.getID());
System.out.println(" time arrived: " + p.getTimeArrived());
System.out.println(" category: " + p.getCategory());
System.out.println("------------------------------------");
t();
} // end doctorVisits method
private void simulate() {
System.out.println("------------------------------------");
System.out.println("ER OPEN");
System.out.println("------------------------------------");
patientArrives(new Patient(100, "high"));
patientArrives(new Patient(101, "low"));
patientArrives(new Patient(102, "low"));
patientArrives(new Patient(103, "high"));
patientArrives(new Patient(104, "high"));
patientArrives(new Patient(105, "low"));
patientArrives(new Patient(106, "low"));
patientArrives(new Patient(107, "high"));
doctorVisits();
doctorVisits();
doctorVisits();
doctorVisits();
doctorVisits();
doctorVisits();
System.out.println("------------------------------------");
System.out.println("ER CLOSED");
System.out.println("------------------------------------");
}
public static void main(String[] args) {
// TODO code application logic here
EmergencyRoomSimulator1 er = new EmergencyRoomSimulator1();
er.simulate();
} // end main
}
Patient.java :
package emergencyroomsimulator1;
import java.util.Date;
public class Patient implements Comparable<Patient> {
protected int id;
protected String category;
protected Date timeArrived;
EmergencyRoomSimulator1 emg;
//protected Date CurrentTime;
// accessors and mutators
public int getID() {
return id;
}
public void setID(int idIn) {
this.id = idIn;
}
public String getCategory() {
return category;
}
public void setCategory(String categoryIn) {
this.category = categoryIn;
}
public java.util.Date getTimeArrived() {
return timeArrived;
}
public int compareTo(Patient other) {
// This code doesn't handle nulls
int result = getCategory().compareTo(other.getCategory());
if (result == 0) {
result = getTimeArrived().compareTo(other.getTimeArrived());
}
return result;
}
// default constructor
public Patient() {
this.id = 0;
this.category = "low"; // unclassified Patients go to the end of the queue
this.timeArrived = new Date();
}
// overloaded constructor
public Patient(int idIn, String categoryIn) {
this.id = idIn;
this.category = categoryIn;
this.timeArrived = new Date();
}
}
PatientComparator.java:
package emergencyroomsimulator1;
import java.util.Comparator;
public class PatientComparator implements Comparator<Patient>{
public int compare(Patient p1, Patient p2) {
int result = p1.getCategory().compareTo(p2.getCategory());
if (result == 0) {
result = p1.getTimeArrived().compareTo(p2.getTimeArrived());
}
return result;
}
}
PatientQueue.java :
package emergencyroomsimulator1;
import java.util.Comparator;
import java.util.PriorityQueue;
public class PatientQueue {
PriorityQueue pq;
// default constructor
public PatientQueue() {
this.pq = new PriorityQueue<Patient>(1, new PatientComparator());
}
public void registerPatient(Patient p) {
this.pq.add(p);
} // end registerPatient method
public Patient getNextPatient() {
return (Patient) this.pq.poll();
} // end getNextPatient method
}

Java Concurrency - Can any one help me with the output . Why list is empty?

Created 2 task which insert values inside list .
Then execute those task using executor service .
And at last try to find out the values inside those list .
Why values are not inserted into list once executor service is shutdown ?
Not able to find out the reason behind this behavior , can any one explain this .
package com.executors;
import java.util.ArrayList;
import java.util.Collections;
import java.util.List;
import java.util.concurrent.Callable;
import java.util.concurrent.ExecutionException;
import java.util.concurrent.ExecutorService;
import java.util.concurrent.Executors;
import java.util.concurrent.Future;
import java.util.concurrent.atomic.AtomicInteger;
public class ExecutorTesting {
public static AtomicInteger counter = new AtomicInteger(0);
static List<employee> list = new ArrayList<employee>();
public static void main(String[] args) throws InterruptedException, ExecutionException {
list = Collections.synchronizedList(list);
Callable<List<employee>> c1 = new Callable<List<employee>>() {
#Override
public List<employee> call() throws Exception {
for (int i = 0; i < 10; i++) {
list.add(new employee("varun", ExecutorTesting.counter.incrementAndGet()));
}
return list;
}
};
Callable<List<employee>> c2 = new Callable<List<employee>>() {
#Override
public List<employee> call() throws Exception {
for (int i = 0; i < 10; i++) {
list.add(new employee("varun", ExecutorTesting.counter.incrementAndGet()));
}
return list;
}
};
ExecutorService es = Executors.newFixedThreadPool(2);
try {
Future<List<employee>> ef1 = es.submit(c1);
Future<List<employee>> ef2 = es.submit(c2);
if (ef1.isDone()) {
System.out.println("first value : " + ef1.get());
}
if (ef2.isDone()) {
System.out.println("first value : " + ef2.get());
}
System.out.println(list);
} finally {
es.shutdown();
}
}
}
class employee {
String name;
int id;
public String getName() {
return name;
}
public void setName(String name) {
this.name = name;
}
public int getId() {
return id;
}
public void setId(int id) {
this.id = id;
}
public employee(String name, int id) {
super();
this.name = name;
this.id = id;
}
public String toString() {
return this.name + " : " + this.id;
}
}
You're calling future.isDone() immediately after submitting it to the ExecuterService. In most cases the execution will not have been started, let alone be finished. So both isDone calls return false and you just finish the whole thing.
I'm not sure about the concrete scenario you're facing, but to solve the problem in this particular test code, you just need to call get on each Future:
System.out.println("first value : " + ef1.get(10, TimeUnit.SECONDS));
System.out.println("first value : " + ef2.get(10, TimeUnit.SECONDS));
I left your copy&paste-error of your output-text ;-)

How to synchronize threads in java

I need to register the order of each customer
The waiter can only deliver orders after write down all requests of your customers.
Customer must wait until the request is delivered
I can not synchronize the client actions with the waiter
I need synchronize each action from my objects Customer and Waiter
Customer has 1 order
Waiter has N customers
The sequence of actions to be synchronized was implemented in the "run" method of each thread
package room;
import java.util.Random;
import java.util.logging.Level;
import java.util.logging.Logger;
public class Customer extends Thread {
private Random random;
private int id;
private static int ID;
private Order order;
private Waiter waiter;
public Customer(Waiter garcom) {
this.random = new Random();
this.id = ID + 1;
Customer.ID++;
this.waiter = garcom;
}
#Override
public void run() {
orderRequest();
waitOrder();
receiveRequest();
consumer();
}
public synchronized void orderRequest() {
synchronized (this.order) {
int r = random.nextInt(3);
switch (r) {
case 0:
this.order.setOrder("Food");
break;
case 1:
this.order.setOrder("Drink");
break;
default:
this.order.setOrder("Help");
break;
}
System.out.println(this.toString() + " request " + this.order.getOrder() + "to " + this.waiter.toString());
this.order.notify();
try {
this.order.wait();
} catch (InterruptedException ex) {
Logger.getLogger(Customer.class.getName()).log(Level.SEVERE, null, ex);
}
}
}
public synchronized void receiveRequest() {
synchronized (this.order) {
this.order.notify();
try {
this.order.wait();
} catch (InterruptedException ex) {
Logger.getLogger(Customer.class.getName()).log(Level.SEVERE, null, ex);
}
System.out.println(this + " has received " + this.order + " from " + this.waiter);
}
}
private void waitOrder() {
synchronized (this.order) {
System.out.println(this + " consumer " + this.order);
this.order.notify();
try {
this.order.wait();
} catch (InterruptedException ex) {
Logger.getLogger(Customer.class.getName()).log(Level.SEVERE, null, ex);
}
}
}
public synchronized void consumer() {
synchronized (this.order) {
System.out.println(this + " was consumed " + this.order);
this.order.notify();
try {
this.order.wait();
} catch (InterruptedException ex) {
Logger.getLogger(Customer.class.getName()).log(Level.SEVERE, null, ex);
}
}
}
public void setOrder(Order order) {
this.order = order;
}
public Order getOrder() {
return order;
}
#Override
public String toString() {
return "Customer: " + id;
}
}
package room;
public class Order {
private int orderNumber;
private static int ORDER_NUMBER = 0;
private Customer customer;
private String order;
public Order(Customer c) {
this.customer = c;
this.orderNumber = ORDER_NUMBER + 1;
this.customer.setOrder(this);
Order.ORDER_NUMBER++;
}
public String getOrder() {
return order;
}
public int getOrderNumber() {
return orderNumber;
}
public void setOrder(String order) {
this.order = order;
}
public Customer getCustomer() {
return customer;
}
#Override
public String toString() {
return "Order: " + order + " Nº " + orderNumber;
}
}
package room;
import java.util.ArrayList;
import java.util.List;
import java.util.logging.Level;
import java.util.logging.Logger;
public class Waiter extends Thread {
private Saloon saloon;
private int id;
private static int ID = 0;
private List<Order> orders;
public Waiter(Saloon bar) {
this.saloon = bar;
this.id = ID + 1;
Waiter.ID++;
this.orders = new ArrayList<>();
}
#Override
public void run() {
while (saloon.isOpen()) {
registerOrder();
deliveryRequest();
saloon.round();
}
}
public synchronized void registerOrder() {
for (Order order : orders) {
synchronized (order) {
order.notify();
try {
order.wait();
} catch (InterruptedException e) {
System.out.println(e.getMessage());
}
System.out.println(this.toString() + " "
+ "record " + order.toString()
+ " to " + order.getCustomer());
}
}
}
public synchronized void deliveryRequest() {
for (Order order : orders) {
synchronized (order) {
order.notify();
try {
order.wait();
} catch (InterruptedException ex) {
Logger.getLogger(Waiter.class.getName()).log(Level.SEVERE, null, ex);
}
System.out.println(this.toString() + " "
+ "delivered " + order.toString()
+ " to " + order.getCustomer());
}
}
}
public synchronized void recordOrder(Order order) {
synchronized (orders) {
this.orders.add(order);
}
}
public List<Order> getOrders() {
return orders;
}
public Saloon getSaloon() {
return saloon;
}
#Override
public String toString() {
return "Waiter: " + id;
}
}
package room;
import java.util.ArrayList;
import java.util.List;
public class Saloon {
private int maxRound;
private int numGarcons;
private volatile int round;
private int capacity;
private int customerCount;
private final List<Waiter> waiters;
public Saloon() {
this.waiters = new ArrayList<>();
this.round = 1;
}
public Saloon(int customerCount, int waiterCount,
int capacity, int rounds) {
this();
this.numGarcons = waiterCount;
this.customerCount = customerCount;
this.capacity = capacity;
this.maxRound = rounds;
}
/**
* Should it be call each round
*/
public void openBar() {
this.capacity = this.customerCount / this.capacity;
System.out.println("Round " + this.round);
for (int i = 0; i < this.numGarcons; i++) {
//Create a waiter
Waiter g = new Waiter(this);
for (int j = 0; j < this.capacity; j++) {
//create customer
Customer c = new Customer(g);
//an order
Order p = new Order(c);
//register order
g.recordOrder(p);
//call thread client
c.start();
}
//waiter serves one client at a time
g.start();
this.waiters.add(g);
}
}
public boolean isOpen() {
if (this.round < this.maxRound) {
return true;
}
return false;
}
public void round() {
this.round++;
}
}
Okay I must say I enjoyed the challenge... But I have figured this out. I should note that I attempted your original maxRounds and though it works there is a bug where 1 extra customer can make it through the queue. NOTE: I am do not claim this is the absolute best way to do this... nor necessarily the most elegant but it should point you towards the right direction.
I would suggest reading about BlockingQueues and classes the extend it.
Main call to the saloon:
public static void main(String[] args) {
Saloon saloon = new Saloon(100, 4, 50);
saloon.openBar();
}
Saloon Class:
package room;
import java.util.ArrayList;
import java.util.List;
public class Saloon {
private volatile static int round;
private static int maxRound;
private int numWaiters;
private final List<Waiter> waiters;
private int customerMax; // current implementation doesn't need this but you could if you wanted
private volatile static boolean isOpen;
private OrderQueue<Order> orderQueue; // This is the creation of the queue
public Saloon() {
this.waiters = new ArrayList<>();
Saloon.round = 1;
}
public Saloon(int customerMax, int numWaiters, int maxRounds) {
this();
this.customerMax = customerMax;
this.numWaiters = numWaiters;
this.orderQueue = new OrderQueue<Order>(numWaiters);
Saloon.maxRound = maxRounds;
}
/**
* Should it be call each round
*/
public void openBar() {
System.out.println("Round " + round);
isOpen = true;
// Create all waiters at once outside the loop
for (int i = 0; i < this.numWaiters; i++) {
waiters.add(new Waiter(i + 1, orderQueue));
waiters.get(i).start();
}
int customersServed = 1; // Generating the id number here is a better choice IMO
while(isOpen) {
for (Waiter waiter : waiters) {
if (round >= maxRound) {
closeBar();
}
if (waiter.isAvailable() && !waiter.isClockedOut()) {
// create customer
Customer customer = new Customer(customersServed++, waiter, orderQueue);
customer.start();
}
}
}
}
/**
* A simple implementation to close the bar
*/
public void closeBar() {
isOpen = false; // ends the loop
int waitersFinished = 0; // used to check if all waiters stopped serving
while (waitersFinished < numWaiters) {
for (Waiter waiter : waiters) {
if (waiter.isAvailable()) {
synchronized (orderQueue) {
// if nothing is currently in the queue for the waiters
if (orderQueue.isEmpty()) {
orderQueue.done(); // close the queue
orderQueue.notify(); // notify the queue
}
waiter.clockOut(); // clockout the waiter could use better implementation
waitersFinished++; // increment waiters finished
}
}
}
}
}
public static boolean isOpen() {
return isOpen;
}
// I would not recommend using this... this is the source of the glitch
public synchronized static void round() {
if (round <= maxRound) { // only if reached maxRounds
System.out.println("Round " + round);
round++;
}
}
}
OrderQueue Class:
package room;
import java.util.concurrent.ArrayBlockingQueue;
/**
*
* Note I did not create this.. tomasb did and I implemented it.
*
* #param <T>
*/
public class OrderQueue<T> extends ArrayBlockingQueue<T> {
private static final long serialVersionUID = 1L;
private boolean done = false;
/**
* creates an order queue with a max capacity.. orders that can be concurrently handled
* #param capacity
*/
public OrderQueue(int capacity) {
super(capacity);
}
/**
* closes the while loop ending this orderqueue
*/
public void done() {
done = true;
}
public boolean isDone() {
return done;
}
/**
* May return null if producer ends the production after consumer has
* entered the element-await state.
*/
public T take() throws InterruptedException {
T el;
while ((el = super.poll()) == null && !done) {
synchronized (this) {
wait();
}
}
return el;
}
}
Order Class:
package room;
public class Order {
private int orderNumber;
private static int ORDER_NUMBER = 0;
private String order;
public Order(int orderNumber) {
this.orderNumber = ORDER_NUMBER + 1;
this.orderNumber = orderNumber;
}
public String getOrder() {
return order;
}
public int getOrderNumber() {
return orderNumber;
}
public void setOrder(String order) {
this.order = order;
}
#Override
public String toString() {
return "Order: " + order + " Nº " + orderNumber;
}
}
Customer Class:
package room;
import java.util.Random;
public class Customer extends Thread {
private int id;
private int orderNumber = 1;
private Order order;
private Waiter waiter;
private OrderQueue<Order> orderQueue; // This provides an esay way to pass objects
public Customer(int id, Waiter waiter, OrderQueue<Order> orderQueue) {
this.id = id;
this.waiter = waiter;
this.orderQueue = orderQueue;
waiter.addCustomer(this);
System.out.println("Customer: " + id + " sat at a table!");
}
#Override
public void run() {
// Notice that wait has been removed. The orderQueue takes care of this.
orderRequest();
receiveRequest();
consumer();
System.out.println("Customer: " + id + " has left satisfied!");
}
public void orderRequest() {
// none of thie should be synchronized as it is local
order = new Order(orderNumber++);
Random random = new Random();
int r = random.nextInt(3);
switch (r) {
case 0:
order.setOrder("Food");
break;
case 1:
order.setOrder("Drink");
break;
default:
order.setOrder("Help");
break;
}
System.out.println(this.toString() + " request " + order.getOrder() + " to " + this.waiter.toString());
// only the call to the orderqueue is synchronized
try {
synchronized (orderQueue) {
orderQueue.put(order);
orderQueue.notify();
}
} catch (InterruptedException e) {
e.printStackTrace();
}
}
public void receiveRequest() {
System.out.println(this + " has received " + this.order + " from " + this.waiter);
}
public void consumer() {
System.out.println(this + " was consumed " + this.order);
}
#Override
public String toString() {
return "Customer: " + id;
}
}
And finally the Waiter Class:
package room;
public class Waiter extends Thread {
private int id;
private Order custOrder;
private Customer customer;
private volatile boolean isAvailable;
private volatile boolean clockOut;
private OrderQueue<Order> orderQueue; // The queue again
public Waiter(int id, OrderQueue<Order> orderQueue) {
this.id = id;
this.orderQueue = orderQueue;
System.out.println("Waiter " + id + " is ready to serve!");
}
#Override
public void run() {
isAvailable = true;
while (!orderQueue.isDone() && !clockOut) {
if (isAvailable) { // this waiter is ready for a task
registerOrder();
isAvailable = false;
synchronized (orderQueue) { // Synchronize this to the queue to prevent worse glitches
Saloon.round();
}
if (custOrder != null) { // error checking
System.out.println(this.toString() + " record " + custOrder.toString() + " to " + customer);
deliveryRequest();
} else {
isAvailable = true;
}
}
}
}
public synchronized void registerOrder() {
try {
custOrder = orderQueue.take(); // this is how you pull the order
} catch (InterruptedException e1) {
System.out.println(true);
}
}
public synchronized void deliveryRequest() {
System.out.println(this.toString() + " " + "delivered " + custOrder.toString() + " to " + customer);
isAvailable = true;
}
public void addCustomer(Customer customer) { // a easy way to add customers to the waiter after creation
this.customer = customer;
isAvailable = false;
}
public Order getOrder() {
return custOrder;
}
#Override
public String toString() {
return "Waiter: " + id;
}
public boolean isAvailable() {
return isAvailable;
}
public void clockOut() {
clockOut = true;
}
public boolean isClockedOut() {
return clockOut;
}
}

Categories