Well, I am a student in the second semester, and now we are going trough threads. I mostly get it, but something is off about one of my exercises and I can't quite understand it.
"In a bakery shop, you often have to take a number when you arrive at the shop and then wait until it is your
turn (with the right number)."
Im going to copy-paste the methods in the monitor where I think the problem might be.
private NumberDispenser(){
nextNoToTake=1;
nextNoToServe=0;
}
public static NumberDispenser accessDispenser(){
if(theOne == null){
theOne = new NumberDispenser();
}
return theOne;
}
#Override
public synchronized void takeNextNumber() {
int currNo = nextNoToTake;
nextNoToTake++;
notifyAll();
System.out.println("No:"+currNo+" has been taken|nextNoToServe:"+nextNoToServe);
while(currNo != nextNoToServe)
{try {
wait();
} catch (InterruptedException e) {}
}
System.out.println("No:"+currNo+" has been served");
notify();
}
#Override
public synchronized int nextCustomer() {//Serves the current customer and goes to the next one
System.out.println("Clerk is ready to deal with a new customer");
while((nextNoToServe)>=nextNoToTake-1)
try {
wait();
} catch (InterruptedException e) {}
nextNoToServe++;
notifyAll();
System.out.println("Now serving No:"+(nextNoToServe));
return nextNoToServe;
}
This is the monitor class. There are two more , for the Customer and for the Clerk , and one more for testing. The customer class has Thread.sleep to simulate time for browsing then goes into dispenser.takeNextNumber();, after which it should finish and the thread responsible for it should die by itself(in the main class).Clerk loops dispenser.nextCustomer() endlessly with a delay.The main method creates , in separate for loops, a number of customers and their threads , and a number of clerks and their threads.
///// This is copy pasted from the requirements.
Customer arrivals and clerk servings are simulated by threads.
Implement as a monitor a class NumberDispencer that implements the interface TakeANumber.
Hint: you could define the two instance variables
private int nextNumberToTake = 1;
private int nextNumberToServe = 1;
Implement two thread classes:
A thread class which simulates customer taking a number and being served
A thread class that simulates clerk serving, that is getting the next customer number and then make
service.
Implement a class with a main method to simulate a bakery shop with e.g. two serving clerks and ten
customers.
/////
I have almost fixed the code. The problem was in the condition of the while loops. Now it works almost as intended, but it skips over the first customer. Only the first customer is skipped, then it all goes how it should.
console output
I can see one place where it is broken.
Hint: Suppose that there is one server and one customer, and the server calls nextCustomer() before a customer arrives. What will wake it up when the customer arrives?
Also, this statement is a hack.
if (nextNoToServe == 0)
nextNoToServe = 1;
That should be dealt with by initializing the instance variables to appropriate values; e.g. in the constructor.
Related
I am currently working on understanding the Java concept of multithreading. I went through a tutorial which uses the Tortoise and the Hare example to explain the concept of multithreading, and to a large extent I understood the syntax and the logic of the video tutorial. At the end of the video tutorial, the Youtuber gave an assignment that involves applying Multithreading to an olympic race track.
Using my knowledege from the example, I was able to create 10 threads (representing the athletes) that run within a loop, that executes 100 times (representing 100 meters).
My challenge is that when the Thread scheduler makes an Athlete to get to 100 meters before the other 9 athletes, the remaining 9 threads always do not complete their race. This is not usually the case in a standard race track. The fact that a Thread called Usain Bolts gets to 100 first, does not mean Yohan Blake should stop running if he is at 90m at that time.
I am also interested in getting the distance (note that they are all using the same variable) for each thread, so that I can use a function to return the positions of each Thread at the end of the race.
What I have done (that did not work):
1) I have tried to use an if else construct (containing nine "else"
statement) to assign the distance of each executing thread to a new integer variable. (using the Thread.currentThread().getName() property and the name of each thread) but that did not work well for me. This was an attempt to give positions to the athletes alone using their distance but does nothing about the 9 athletes not finishing the race.
2) I have also tried to use an ArrayList to populate the distance at runtime but for some strange reasons this still overwrites the distance each time it wants to add another distance.
Below are my codes:
package olympics100meters;
import java.util.ArrayList;
public class HundredMetersTrackRules implements Runnable {
public static String winner;
public void race() {
for (int distance=1;distance<=50;distance++) {
System.out.println("Distance covered by "+Thread.currentThread ().getName ()+" is "+distance+" meters.");
boolean isRaceWon=this.isRaceWon(distance);
if (isRaceWon) {
ArrayList<Integer> numbers = new ArrayList();
numbers.add(distance);
System.out.println("testing..."+numbers);
break;
}
}
}
private boolean isRaceWon(int totalDistanceCovered) {
boolean isRaceWon=false;
if ((HundredMetersTrackRules.winner==null)&& (totalDistanceCovered==50)) {
String winnerName=Thread.currentThread().getName();
HundredMetersTrackRules.winner=winnerName;
System.out.println("The winner is "+HundredMetersTrackRules.winner);
isRaceWon=true;
}
else if (HundredMetersTrackRules.winner==null) {
isRaceWon=false;
}
else if (HundredMetersTrackRules.winner!=null) {
isRaceWon=true;
}
return isRaceWon;
}
public void run() {
this.race();
}
}
This is my main method (I reduced it to 5 Athletes till I sort out the issues):
public class Olympics100Meters {
/**
* #param args the command line arguments
*/
public static void main(String[] args) {
HundredMetersTrackRules racer=new HundredMetersTrackRules();
Thread UsainBoltThread=new Thread(racer,"UsainBolt");
Thread TysonGayThread=new Thread (racer,"TysonGay");
Thread AsafaPowellThread=new Thread(racer,"AsafaPowell");
Thread YohanBlakeThread=new Thread (racer,"YohanBlake");
Thread JustinGatlinThread=new Thread (racer,"JustinGatlin");
UsainBoltThread.start();
TysonGayThread.start();
AsafaPowellThread.start();
YohanBlakeThread.start();
JustinGatlinThread.start();
}
}
My challenge is that ... the remaining 9 threads always do not complete their race.
This is caused by isRaceWon() method implementation. You check for it at each meter at each runner. As soon as the first runner achieves 100 meters, the break is called on next step of each runner loop (the race is won for every loop
btw, it makes sense to use volatile statuc String for winner's name, to avoid java's memory model ambiguities.
I am also interested in getting the distance ... for each thread, so that I can use a function to return the positions of each Thread at the end of the race.
If the final aim is to get the position, create a class field public List<String> finishingOrder = new ArrayList<String> and a method finish
private synchronized finish() {
finishingOrder.add(Thread.currentThread().getName())
}
and call it after the "run" loop
do not forget to call join() for all runner threads in your main. After that, the finishingOrder will contain names in order of finishing.
The code snippet below is causing isRaceWon to return true for every instance of HundredMetersTrackRules as soon as the shared winner field is set to non-null (i.e. someone wins.):
else if (HundredMetersTrackRules.winner!=null) {
isRaceWon=true;
}
This in turn causes the loop in race() to break for every instance of your Runnable. The run() method exits, terminating the thread.
The issue is just a logic error and not really specific to threading. But, as other posters have mentioned, there's some threading best-practices you can also adopt in this code, such as using volatile for fields shared by threads.
Actually For Race you need to start all the Threads at once then only its Race.
CountDownLatch is better one to Implement or write Race Program.
Many other way also we can write Race program without using the CountDownLatch.
If we need to implement using base / low level then we can use volatile boolean Flag and counter variable in synchronized blocks or using wait() and notifyAll() logic, etc.,
Introduced some time delay in your program inside the for loop. Then only you can feel the Experience. Why because you are not starting all the threads at once.
Hope you are Practicing Initial / base Level so I made few changes only for better understanding and Addressed all your queries.
import java.util.ArrayList;
import java.util.List;
import java.util.Collections;
class HundredMetersTrackRules implements Runnable {
public static Main main;
HundredMetersTrackRules(Main main){
this.main=main;
}
public static String winner;
public void race() {
try{
System.out.println(Thread.currentThread().getName()+" Waiting for others...");
while(!Main.start){
Thread.sleep(3);
}
for (int distance=1;distance<=50;distance++) {
System.out.println("Distance covered by "+Thread.currentThread().getName()+" is "+distance+" meters.");
Thread.sleep(1000);
}
synchronized(main){
Main.finish--;
}
Main.places.add(Thread.currentThread().getName());
}catch(InterruptedException ie){
ie.printStackTrace();
}
}
public void run() {
this.race();
}
}
public class Main
{
public static volatile boolean start = false;
public static int finish = 5;
final static List<String> places =
Collections.synchronizedList(new ArrayList<String>());
public static void main(String[] args) {
HundredMetersTrackRules racer=new HundredMetersTrackRules(new Main());
Thread UsainBoltThread=new Thread(racer,"UsainBolt");
Thread TysonGayThread=new Thread (racer,"TysonGay");
Thread AsafaPowellThread=new Thread(racer,"AsafaPowell");
Thread YohanBlakeThread=new Thread (racer,"YohanBlake");
Thread JustinGatlinThread=new Thread (racer,"JustinGatlin");
UsainBoltThread.start();
TysonGayThread.start();
AsafaPowellThread.start();
YohanBlakeThread.start();
JustinGatlinThread.start();
Main.start=true;
while(Main.finish!=0){
try{
Thread.sleep(100);
}catch(InterruptedException ie){
ie.printStackTrace();
}
}
System.out.println("The winner is "+places.get(0));
System.out.println("All Places :"+places);
}
}
I am doing the chef, bread, and customer scenario in Java with thread. So basically the chef makes a bread, the customer eats it, the chef makes more. The maximum is 20. The chef stop making bread when there are 20. The customer stop eating when there is none left. But everytime I use notifyall, it wait four seconds before the customer eat it(supposed to make 3 more breads).
Here is the code for run in the Chef class(implements runnable)
public void run(){
int id = 0;
while(true){
if(Basket.breadList.size() == 20){
synchronized(Basket.breadList){
try {
Basket.breadList.wait();
} catch (InterruptedException e) {
// TODO Auto-generated catch block
e.printStackTrace();
}
}
}
Bread bread = new Bread(id);
System.out.println("Bread " + id + " had just been made. ");
synchronized(Basket.breadList){
Basket.breadList.notifyAll();
try {
Thread.sleep(1000);
} catch (InterruptedException e) {
e.printStackTrace();
}
id++;
}
}
}
Here is the code for Customer:
public void run(){
int id;
while(true){
if(Basket.breadList.size() == 0){
synchronized(Basket.breadList){
try {
Basket.breadList.wait();
} catch (InterruptedException e) {
e.printStackTrace();
}
}
}
id = Basket.breadList.get(Basket.breadList.size()-1).id;
Basket.breadList.remove(Basket.breadList.size()-1);
System.out.println("Bread " + id + " had just been eaten. ");
synchronized(Basket.breadList){
Basket.breadList.notifyAll();
try {
Thread.sleep(4000);
} catch (InterruptedException e) {
e.printStackTrace();
}
}
}
}
Here is the code in the controller:
public static void main(String[] args) {
Chef chef = new Chef();
Customer customer = new Customer();
Thread t1 = new Thread(chef);
Thread t2 = new Thread(customer);
t1.start();
try {
Thread.sleep(20);
} catch (InterruptedException e) {
// TODO Auto-generated catch block
e.printStackTrace();
}
t2.start();
}
Basket.breadList is just an arraylist of breads.
please help. Much appreciated!
After your Customer eats any bread whatsoever, it always waits 4 seconds. There is nothing to prevent this wait (typically some if () should be in place).
Rule: never sleep() unconditionally, unless you absolutely sure this is how it is supposed to be. You always sleep() because there is nothing else to accomplish and probably will not be for a while. So you need to check if there is.
Also, notifyAll() is typically done immediately after some prior action that makes things available for other threads to process.
Rule: call notifyAll() on a container immediately after you put something in it.
It is also not clear, in which code and at what time Chef adds the Bread to the basket. I assume bread adds itself in its own constructor - if so, it is an anti-pattern. Keep bread simple and healthy, it will taste better this way. Make Chef do the work. I would freak out if, while kneading and baking itself bread crawls into the basket.
Generally speaking, try to write your code exactly as actors in real world would act. Would Chef notify customer basket is not empty? When? Would customer notify Chef when basket is empty? When? When does either of them wait?
Your code is not locking effectively, so that while one thread is working the other can tamper with the data. Here's an example showing a better way for the backer to bake a loaf of bread, then wait while the bread supply is maxed out, then add the loaf to the inventory:
try {
while (true) {
Thread.sleep(4000);
Bread bread = new Bread(id++);
synchronized(Basket.breadList) {
while (Basket.breadList.size() == 20) {
Basket.breadList.wait();
}
Basket.breadList.add(bread);
Basket.breadList.notifyAll();
}
}
} catch (InterruptedException e) {
}
The wait method releases the lock, then re-acquires the lock before it can exit. Since this example holds the lock while it is checking and acting, once the inner while loop is exited from it is certain that the breadList contains less than 20 items. The customer should be rewritten similarly.
This version waits in a loop while holding the lock, checking the condition after emerging from the wait, because something may have changed while your thread didn't have the lock.
Also, just because your thread woke up doesn't mean you got a notification. The wait method can exit without having received a notification. See the Oracle tutorial for how to use wait and notify.
The only way for your thread to know what the size of the list really is is to check it while holding the lock, otherwise it could be changing on you (the other thread can be swapped in and change something in between your check and whatever action you take), resulting in the first thread basing its decisions on possibly stale information.
Likewise your customer shouldn't be removing something from the shared list without holding the lock on it. ArrayList is not threadsafe, also you don't want the state to change in between removing an item and sending the notification. If you are removing something from the list and then want to perform a notification, acquire the lock, then do the removal and notify together while holding the lock.
Don't hold a lock while sleeping, it's pointless and bad for performance. It would be better in this example, if you want to simulate needing time to create bread, for the sleep to come before the call to the Bread constructor.
The way your code swallows InterruptedException doesn't help your thread actually exit cleanly once interrupted. If you catch the InterruptedException outside the while (true) loop then the thread will respond to interruption by actually quitting its work and terminating.
The baker and customer should not be in charge of locking, it's confusing and makes it harder to understand how multithreading is applicable to real-life situations. Use a queue here, making the baker a producer and the customer a consumer. You have a shared data structure already, the arrayList, but you chose a data structure that isn't threadsafe and can't do blocking, the shared data structure needs to be in charge of protecting its own integrity. That way the roles are much clearer, with the locking, waiting, and notifying taking place in the shared data structure and not in the threads. Using a blocking queue from the java.util.concurrent package would be a good choice here, or write your own if you want the experience, it should be do-able once you read the linked tutorial. Once you use a separate queue the run method for the baker becomes:
public void run() {
try {
int id = 0;
while (true) {
Thread.sleep(4000);
queue.put(new Bread(id++));
}
} catch (InterruptedException e) {
}
}
while the queue's put method would be
public synchronized void put(Bread b) throws InterruptedException {
while (breadList.size() == 20) {
wait();
}
breadList.add(b);
notifyAll();
}
assuming that breadList is a private instance member of the Queue.
I am having a very hard time trying to understand the concept of synchronizing methods, objects and understand the main issue of not doing so, when running a multi-threaded application.
I understand that synchronize keyword is used to make sure that only one thread will work with a specific object or enter a specific block or method in a time, basically locks it and unlocks when the execution ended, so the other threads can enter it.
But I don't really understand the problem, I am totally confused, I created a demo application, where I have 2 bank accounts, and one bank class which has 5000 funds and a method that transfers a specific amount of money to the given account, and in it's constructor it creates the 2 bank accounts and start the threads (each account is a thread).
Now in the bank account's class I have a funds field, and a run method which the thread will call upon start (the class inheriting Thread), and the run method will loop 10 times, and take 20 dollar from the main bank by calling Bank#takeFunds(int amount)
So there we go, the Bank class:
public class Bank {
private int bankmoney = 5000;
public Bank() {
Client a = new Client(this);
Client b = new Client(this);
a.start();
b.start();
}
public void takeMoney(Client c, int amount) {
if (bankmoney >= amount) {
bankmoney -= amount;
c.addFunds(amount);
}
}
public void print() {
System.out.println("left: " + bankmoney);
}
public static void main(String... args) {
new Bank();
}
}
And the Client class:
public class Client extends Thread {
private Bank b;
private int funds;
Random r = new Random();
public Client(Bank b) {
this.b = b;
}
public void addFunds(int funds) {
this.funds += funds;
}
public void run() {
for (int i = 0; i < 10; i++) {
b.takeMoney(this, 20);
}
System.out.println(Thread.currentThread().getName() + " : " + funds);
b.print();
}
}
And the output for me:
Thread-0 : 200
left: 4800
Thread-1 : 200
left: 4600
The program ends with 200$ in each account, and 4600 left in the bank, so I don't really see the issue, I am failing to demonstrate the issue of thread safety, and I think this is why I can't understand it.
I am trying to get the most simple explanation on how it works exactly, How can my code turn into a problem with thread safety?
Thanks!
Example:
static void transfer(Client c, Client c1, int amount) {
c.addFunds(-amount);
c1.addFunds(amount);
}
public static void main(String... args) {
final Client[] clients = new Client[]{new Client(), new Client()};
ExecutorService s = Executors.newFixedThreadPool(15);
for (int i = 0; i < 15; i++) {
s.submit(new Runnable() {
#Override
public void run() {
transfer(clients[0], clients[1], 200);
}
});
}
s.shutdown();
while(!s.isTerminated()) {
Thread.yield();
}
for (Client c : clients) {
c.printFunds();
}
}
Prints:
My funds: 2000
My funds: 8000
To start with, a thread is not an object. Do not assign a separate thread to each client. Threads do work and objects contain code which specifies what must be done.
When you call methods on a Client object, they do not execute "on that client's thread"; they execute in the thread from which they are called.
In order to make a thread do some work, you need to hand it over an object implementing the code to be executed on it. That's what an ExecutorService allows you to do simply.
Also keep in mind that locks do not "lock objects" and synchronized(anObject) will not on its own stop another thread from calling anObject's methods at the same time. Locks only prevent other threads trying to acquire the same lock from proceeding until the first thread is done with it.
I tested your program, and in fact got the following output:
(The result is not 4600 as in your case.)
The point is that just because it happens to work once doesn't mean that it will always work. Multi threading can (in an illsynchronized program) introduce non-determinism.
Imagine what would happen if your operations took a bit longer to execute. Let's simulate this with a Thread.sleep:
public void takeMoney(Client c, int amount) {
if (bankmoney >= amount) {
try { Thread.sleep(1000); } catch (InterruptedException e) { }
bankmoney -= amount;
c.addFunds(amount);
}
}
Now try running your program again.
your program is working fine , as you are only deducting total amount of 2000. Which is far lesser than initial value. So, this check has no play, you code will work even if you rmeove it.
if (bankmoney >= amount) {
The only bad thing that can happen in this scenario , if client1 checks that amount is more than he needs to withdraw , but in meantime other client withdraws it.
public void run() {
for (int i = 0; i < 100; i++) {
b.takeMoney(this, 200);
}
System.out.println(Thread.currentThread().getName() + " : " + funds);
b.print();
}
public void takeMoney(Client c, int amount) {
if (bankmoney >= amount) {
system.println("it is safer to withdraw as i have sufficient balance")
bankmoney -= amount;
c.addFunds(amount);
}
}
there will be time when client one will check bankmoney is greater than amount , but when he withdraws, it will reach to negative amount. as other thread will take that amount.
Run program, 4-5 times you will realize.
Let's look at a more realistic example and implement a transfer function for our Bank:
public boolean transfer(long amount, Client source, Client recipient) {
if(!source.mayTransferAmount(amount)) return false; // left as an exercise
source.balance -= amount;
recipient.balance += amount;
}
Now let's imagine two threads. Thread A transfers a single unit from Client x to Client y while Thread B transfers a single unit from Client y to Client x. Now you must know that without synchronization, you cannot be sure how the CPU orders operations, so it could be:
A: get x.balance (=100) to tmpXBalance
B: get x.balance (=100) to tmpXBalance
B: increment tmpXBalance (=101)
B: store tmpXBalance to x.balance (=101)
A: decrement tmpXBalance (=99)
A: store tmpXBalance to x.balance (=99)
(rest of exchange omitted for brevity)
Whoa! We just lost money! Client x won't be very happy. Note that locking alone won't give you any guarantee, you also need to declare balance as volatile.
Any time there's something you want to do to data that are shared by more than one thread, if it takes more than one step, then you probably need synchronization.
This takes three steps:
i++;
The steps are; (1) get the value of i from memory into a register, (2) add 1 to the register, (3) store the value of the register back into memory.
A running thread can be preempted at any time. That means, the operating system can pause it, and give some other thread a turn using the CPU. So, if there's no synchronization, thread A could perform step (1) of incrementing i (it could get the value into a register), and then it could be preempted. While thread A is waiting to run again, threads B, C, and D could each increment i a thousand times. Then when thread A finally got to run again, it would add 1 to the value that it originally read, and then store that back into memory. The three thousand increments by threads B, C, and D would be lost.
You need synchronization whenever one thread could put some data into a temporary state that you don't want other threads to see or operate on. The code that creates the temporary state must be synchronized, and any other code that could operate on the same data must be synchronized, and any code that merely allows a thread to see the state must synchronized.
As Marko Topolnik pointed out, synchronization doesn't operate on data, and it doesn't operate on methods. You need to make sure that all of the code that modifies or looks at a particular collection of data is synchronized on the same object. That's because synchronization does one thing, and one thing only:
The JVM will not allow two threads to be synchronized on the same object at the same time. That's all it does. How you use that is up to you.
If your data are in a container, it may be convenient for you to synchronize on the container object.
If your data are all instance variables of the same Foobar instance, then it may be convenient for you to synchronize on the instance.
If your data are all static, then you probably should synchronize on some static object.
Good luck, and have fun.
So I need to make an elevator simulator, and I was wondering how can I go about continuously generating people to call the elevator. I need this to go on forever. So basically a person is created and calls the elevator. All of these calls are kept track of but I think I need to keep track of the people who are actually on the elevator too.
I have a few classes Person, Elevator, ElevatorCall & ElevatorCallQueue.
In Person I have a run() method which basically makes an Elevator call with the current floor and destination floor and then I have a BlockingQueue that I put the call on. This run method just runs while true.
In ElevatorCall I just have getters and setters for the collection and destination floors
In ElevatorCallQueue, I have variables for MAX_CALLS and numberOfPeople.
I have a BlockingQueue<ElevatorCall> queue = new ArrayBlockingQueue<ElevatorCall>(MAX_CALLS)
and a List<Person>
I add people to the list and I run through the list and start the run() method on each person. Finally I create an elevator and provide the queue, and run it.
In Elevator I have the BlockingQueue<ElevatorCalls>. I have a while(true) here also, and inside it I make an ArrayList<ElevatorCall> and then I use the BlockingQueues drainTo method using the ArrayList<ElevatorCalls> as a parameter.
The rest of the run() method basically iterates through the array list and does what an elevator does, so It goes to the first pressed button, checks each floor for people and if it is a destination floor.
Right now I've gotton stuck and dont know where to go from here. I need to some how have People continiously added and calling the elevator, and have the Elevator wait if there is no more calls. Would appreciate it if anybody could help put me in the right direction.
Thanks
EDIT
Here is the code to the elevator class as somebody said I should post some code. However I'm not sure what code to post so I thought I'd just put in the entire class
I think everyone's jumped at the word concurrency very quickly - don't let it cloud your judgement. I can't speak on behalf your exact problem/criteria but an elevator goes about travelling to floors, with the only disturbance being a new person pressing a button. So, why not give elevator a method simulate(int time) that does this, and a method new_person(person p) which adds another person to the queue. Then just generate a random time interval, simulate the elevator, add a new person with random floor destination and source, and then repeat.
But you say it has to be concurrent -
Well your question seems to be where do the elevatorcalls come from?
This is an instance of the typical producer consumer pattern. What's that you ask?
Well the oracle documentation for BlockingQueue gives a better example than I ever could
class Producer implements Runnable {
private final BlockingQueue queue;
Producer(BlockingQueue q) { queue = q; }
public void run() {
try {
while (true) { queue.put(produce()); }
} catch (InterruptedException ex) { ... handle ...}
}
Object produce() { ... }
}
class Consumer implements Runnable {
private final BlockingQueue queue;
Consumer(BlockingQueue q) { queue = q; }
public void run() {
try {
while (true) { consume(queue.take()); }
} catch (InterruptedException ex) { ... handle ...}
}
void consume(Object x) { ... }
}
class Setup {
void main() {
BlockingQueue q = new SomeQueueImplementation();
Producer p = new Producer(q);
Consumer c1 = new Consumer(q);
Consumer c2 = new Consumer(q);
new Thread(p).start();
new Thread(c1).start();
new Thread(c2).start();
}
}
Hmm.. Can you see how this relates to your problem? You've already solved half of it.
The Elevator acts as the consumer of elevatorCalls, you seem to be struggling with who produces them. This is a job for a new thread that runs an ElevatorCall producers. See if you can work the rest out.
So I am working on this program that simulates a day at work and each worker is its own thread. I'm trying to implement meetings where the workers attend meetings but the meetings do not start until everyone that is supposed to be at the meeting has arrived. So I have this method for attending the meeting.
public void attendMeeting(Employee worker){
this.cdStart.countDown();
worker.meetingWait();
try {
this.cdStart.await();
worker.meetingStart(this.length);
if(this.attendees.get(0).equals(worker)){
this.room.exit();
} // end if
} // end try
catch (InterruptedException err) {
// Do Nothing
} // end catch
} // end method attendMeeting
The worker parameter being an instance of the Employee class that extends Thread and this.cdStart is the CountDownLatch. However, when running this with a meeting of four employees, only one employee seems to be able to get in, decrement the count, and hit the await() call. None of the other worker threads seem to be able to enter it. I did notice that a lot of the online examples of use pass the CountDownLock object to the threads themselves to handle. Is there a reason why this would not work instead?
I am assuming you are having a single thread pass in an Employee Thread object. That single thread will be waiting indefinitely until the N number of parties arrive (you need an individual thread for each Employee instance aside from the Employee thread). This means that if only one thread is continuously passing the Employee/Thread you will never get more then one Employee waiting at the meeting.
This thread should instead, at best, signal the Employee threads to attend the Meeting.
You should have the latch in the Meeting class and have them await on that latch. This also requires a slight restructure of the way it works.
You pass the Meeting instance into the Employee to have that thread wait.
public Employee extends Thread{
//define this at some point whether in constructor or a
//means of notifying the thread to attend the meeting
private Meeting meeting;
public void run(){
//do some stuff until this employee is ready to go to a meeting
meeting.waitForAllOthersToArrive();
}
}
public class Meeting{
CountDownLatch latch = new CountDownLatch(numberOfEmployees);
public void waitForAllOthersToArrive(){
latch.countDown();
latch.await();
}
}
What I would suggest for this however is a CylicBarrier. Though you wouldn't be re using it, the way the CyclicBarrier works fits better what you're trying to do, the Meeting class would then look like
public class Meeting{
CylicBarrier barrier = new CylicBarrier(numberOfEmployees);
public void waitForAllOthersToArrive(){
barrier.await(); //when await() is called numberOfEmployees then all waiting threads will awake
}
}