I created a project for studying purposes that simulates a restaurant service using Threads. There is a Thread for Cook(s) to prepare a meal and another Thread for Waiter(s) to serve the meal. When I tested it with 1 cook and 5 waiters, it worked fine. But when I increase the number of cooks, the program runs indefinitely. What is wrong? Here is the code:
Class Main
package restaurant;
import java.util.concurrent.Semaphore;
public class Main {
public static int MAX_NUM_MEALS = 5;
public static int OLDEST_MEAL = 0;
public static int NEWEST_MEAL = -1;
public static int DONE_MEALS = 0;
public static int NUM_OF_COOKS = 1;
public static int NUM_OF_WAITERS = 5;
public static Semaphore mutex = new Semaphore(1);
static Cook cookThreads[] = new Cook[NUM_OF_COOKS];
static Waiter waiterThreads[] = new Waiter[NUM_OF_WAITERS];
public static void main(String[] args) {
for(int i = 0; i < NUM_OF_COOKS; i++) {
cookThreads[i] = new Cook(i);
cookThreads[i].start();
}
for(int i = 0; i < NUM_OF_WAITERS; i++) {
waiterThreads[i] = new Waiter(i);
waiterThreads[i].start();
}
try {
for(int i = 0; i < NUM_OF_COOKS; i++) {
cookThreads[i].join();
}
for(int i = 0; i < NUM_OF_WAITERS; i++) {
waiterThreads[i].join();
}
}catch(InterruptedException e) {
e.printStackTrace();
}
System.out.println("All done");
}
}
Class Cook
package restaurant;
public class Cook extends Thread{
private int id;
public Cook(int id) {
this.id = id;
}
public void run() {
while(true) {
System.out.println("Cook " + id + " is prepearing meal");
try {
Thread.sleep(1000);
Main.mutex.acquire();
Main.NEWEST_MEAL++;
Main.mutex.release();
Main.mutex.acquire();
Main.DONE_MEALS++;
Main.mutex.release();
System.out.println("Cook " + id + " has finished the meal");
if(Main.DONE_MEALS == 5) {
System.out.println("Cook " + id + " has finished his job");
break;
}
} catch (InterruptedException e) {
// TODO Auto-generated catch block
e.printStackTrace();
}
}
}
}
Class Waiter
package restaurant;
public class Waiter extends Thread{
private int id;
public Waiter(int id) {
this.id = id;
}
public void run() {
while(true) {
System.out.println("Waiter " + id + " will check if there is any meal to serve");
if(Main.NEWEST_MEAL >= Main.OLDEST_MEAL) {
try {
Main.mutex.acquire();
Main.OLDEST_MEAL++;
Main.mutex.release();
System.out.println("Waiter " + id + " is picking up meal");
Thread.sleep(500);
System.out.println("Waiter " + id + " has delivered the meal to client");
} catch (InterruptedException e) {
// TODO Auto-generated catch block
e.printStackTrace();
}
}
if(Main.DONE_MEALS == 5) {
System.out.println("Waiter " + id + " has finished his job");
break;
}
System.out.println("No meal to serve. Waiter " + id + " will come back later");
try {
Thread.sleep(100);
} catch (InterruptedException e) {
// TODO Auto-generated catch block
e.printStackTrace();
}
}
}
}
Two issues:
Because you have two cooks, one of your cooks likely won't see Main.DONE_MEALS == 5. It will jump from 4 to 6 because of the other cook. Instead, check for Main.DONE_MEALS >= 5.
There is no guarantee that the cook or waiter threads will see the updates to Main.DONE_MEALS. Instead, consider having a private static final AtomicInteger field. The AtomicInteger class is a thread-safe integer implementation that enables other threads to see it in a thread-safe way.
The traditional fix would be:
a) You have to use the lock (mutex) not only when you write, but also when you read - otherwise it won't work correctly.
Just imagine you agreed on a signal to indicate if the bathroom is busy, but some just decide to ignore it - won't work!.
b) Check the condition before you do something.
Once you acquire the lock, you don't know the state so you should first check it before you proceed to make another meal. If you first check if there are already 5 done meals and only produce meals if there aren't yet 5, it should fix this problem, and you should only ever see done_meals <= 5 (you should review other parts of the code because it has similar problems, though).
Like others have mentioned, there are cleaner ways to write this but IMO your code is very suited for practice and understanding, so I'd try that rather than jumping for things like AtomicInteger.
Related
I have a Java program that is simulating one way tunnel. A semaphore represents the tunnel, and there are two threads that represent the queues of traffic waiting on either side to pass through. In main, both threads are started as well as a thread to generate cars on either side every second. When a thread realizes its queue has cars in it, it attempts to acquire the semaphore. Once it has it, it allows each car to pass through, and releases the semaphore for the other side to use.
My problem is that it only is able to pass cars on the first try. After one side has claimed and released the semaphore, it seems that it will not be able to send cars through again. It seems to be that the if statement that is checking for cars in the queue is not executing.
class leftManager extends Thread {
private int leftQueue = 0;
private int total = 0;
static Semaphore semaphore;
public leftManager(Semaphore semaphore) {
this.semaphore = semaphore;
this.leftQueue = leftQueue;
}
public int getQueue() {
return leftQueue;
}
public void setQueue(int x) {
leftQueue += x;
}
#Override
public void run() {
try {
while (true) {
if (leftQueue > 0) {
System.out.println("Catch");
semaphore.acquire();
for (int i = 1; i <= leftQueue; i++) {
int temp = (leftQueue - (leftQueue - (i - 1)));
leftBoundPass pass = new leftBoundPass((temp * 2) + total);
pass.start();
try {
leftManager.sleep(1000);
} catch (InterruptedException e) {
e.printStackTrace();
}
}
total += leftQueue;
leftQueue = 0;
semaphore.release();
System.out.println("release");
}
else {
continue;
}
}
}
catch (InterruptedException e) {
e.printStackTrace();
}
}
}
The rightManager is identical, other than different variable names and a different "boundPass" thread for the cars.
class leftBoundPass extends Thread {
private int car;
public leftBoundPass(int car) {
this.car = car;
}
#Override
public void run() {
System.out.println("Left-bound car " + car + " is in the tunnel.");
//This is one second of sleep
try {
leftBoundPass.sleep(1000);
} catch (InterruptedException e) {
e.printStackTrace();
}
System.out.println("Left-bound car " + car + " is exiting the tunnel.");
}
}
The car generator is as follows:class trafficGenerator extends Thread {
leftManager left;
rightManager right;
public trafficGenerator(leftManager left, rightManager right) {
this.left = left;
this.right = right;
}
#Override
public void run() {
int random;
while (true) {
random = (int)(Math.random() * 2);
if (random == 0) {
System.out.println("Left-bound car wants to enter the tunnel");
left.setQueue(1);
//System.out.println(left.getQueue());
}
else {
System.out.println("Right-bound car wants to enter the tunnel");
right.setQueue(1);
}
try
{
Thread.sleep(2000);
}
catch(Exception e)
{
System.err.println(e);
}
}
}
}
Output:
Left-bound car wants to enter the tunnel
Catch
Left-bound car 0 is in the tunnel.
Left-bound car 0 is exiting the tunnel.
release
Left-bound car wants to enter the tunnel
Right-bound car wants to enter the tunnel
Right-bound car wants to enter the tunnel
I have a bunch of threads that spawn somewhat arbitrarily. When they are racing each other, only the one that spawned last is relevant. The other threads can be thrown away or stopped. But I am not sure how to do that, so I have implemented a very basic counter that checks whether the thread is the latest spawned thread.
edit: I would like to be able to kill threads that are taking too long (as they are no longer necessary); probably not from within the threads themselves as they are busy doing something else.
This code works, it seems. But it doesn't feel robust. Can someone give me a hint toward a proper way to do this?
class Main {
private static volatile int latestThread = 0;
public static void main(String[] args) {
for (int i = 0; i < 10; i++) {
spawnThread();
}
}
private static void spawnThread() {
latestThread++;
int thisThread = latestThread;
new Thread(() -> {
try {
Thread.sleep(10);
} catch (InterruptedException e) {
e.printStackTrace();
}
if (latestThread == thisThread) {
// only the latest "active" thread is relevant
System.out.println("I am the latest thread! " + thisThread);
}
}).start();
}
}
output:
I am the latest thread! 10
code in replit.com
ThreadPoolExecutor is almost what I need, specifically DiscardOldestPolicy. You can set the queue size to 1, so one thread is running and one thread is in the queue, and the oldest in the queue just gets shunted. Clean!
But it finishes two threads (not only the latest), which is not 100% what I was looking for. Although arguably good enough:
import java.util.concurrent.ArrayBlockingQueue;
import java.util.concurrent.ThreadPoolExecutor;
import java.util.concurrent.TimeUnit;
import java.util.concurrent.atomic.AtomicInteger;
public class DiscardOldest {
private static int threadCounter = 1;
public static void main(String[] args) throws InterruptedException {
int poolSize = 0;
int maxPoolSize = 1;
int queueSize = 1;
long aliveTime = 1000;
ArrayBlockingQueue<Runnable> queue = new ArrayBlockingQueue<>(queueSize);
ThreadPoolExecutor executor = new ThreadPoolExecutor(poolSize, maxPoolSize, aliveTime, TimeUnit.MILLISECONDS, queue, new ThreadPoolExecutor.DiscardOldestPolicy());
for (int i = 0; i < 4; i++) {
spawnThread(executor);
}
}
private static void spawnThread(ThreadPoolExecutor executor) {
final int thisThread = threadCounter++;
System.out.println(thisThread + " spawning");
executor.execute(() -> {
try {
Thread.sleep(100);
System.out.println(thisThread + " finished!");
} catch (InterruptedException e) {
e.printStackTrace();
}
});
}
}
Ouput:
1 spawning
2 spawning
3 spawning
4 spawning
1 finished!
4 finished!
Rather than relaying on an index, a born time could be set. If there's a younger thread (was born later) the thread should terminate its execution.
public class Last {
private static volatile long latestThread = 0L;
/**
* #param args
*/
public static void main(String[] args) {
for (int i = 0; i < 3; i++) {
spawnThread(System.nanoTime(), i);
}
}
private static void spawnThread(long startTime, int index) {
new Thread(() -> {
latestThread = startTime;
long thisThread = startTime;
boolean die = false;
try {
while (!die) {
Thread.sleep(1);
if (thisThread < latestThread) {
System.out.println(
index + ": I am not the latest thread :-(\n\t" + thisThread + "\n\t" + latestThread);
die = true;
} else if (thisThread == latestThread) {
System.out.println(
index + ": Yes! This is the latest thread!\n\t" + thisThread + "\n\t" + latestThread);
Thread.sleep(1);
System.out.println("Bye!");
die = true;
}
}
} catch (InterruptedException e) {
e.printStackTrace();
}
}).start();
}
}
Result:
0: I am not the latest thread :-(
39667589567880
39667602317461
2: Yes! This is the latest thread!
39667602317461
39667602317461
1: I am not the latest thread :-(
39667602257160
39667602317461
Bye!
I did a little research based on comments from everybody (thanks!) and ThreadPoolExecutor is almost what I need, but I want a pool with the total size of 1 (no queue) that kills the active thread once a new thread comes along, which is not allowed in a thread pool and not in line with what a ThreadPool is for. So instead, I came up with a reference to the active thread, and when a new thread comes a long it kills the old one, which seems to do what I want:
import java.util.concurrent.atomic.AtomicInteger;
public class Interrupt {
private static final AtomicInteger CURRENT_THREAD = new AtomicInteger(0);
private static Thread activeThread = new Thread(() -> {});
public static void main(String[] args) throws InterruptedException {
for (int i = 0; i < 4; i++) {
spawnThread();
Thread.sleep(3);
}
}
private static void spawnThread() {
if (activeThread.isAlive()) {
activeThread.interrupt();
}
activeThread = new Thread(() -> {
int thisThread = CURRENT_THREAD.incrementAndGet();
System.out.println(thisThread + " working");
try {
Thread.sleep(1000);
System.out.println(thisThread + " finished!");
} catch (InterruptedException ignored) {}
});
activeThread.start();
}
}
Output:
3 working
2 working
1 working
4 working
4 finished!
I don't understand my mistake, i will describe it and then i will post my code.
From main() i want to run 3 threads (each thread containing a loop for 3 women).
I have a method that prints each woman that enters the bathroom and each woman that out.I want to use lock so every 3 women in each thread would be written before the next thread will take place.the out put should be something like this:
woman 0 enters the bathroom
woman 0 exits the bathroom
woman 1 enters the bathroom
woman 1 exits the bathroom
woman 2 enters the bathroom
woman 2 exits the bathroom
and then 2 times for each thread.
my problem is that only one thread is writing and 2 that didnt reach the lock still waiting after i release the lock.
here is my code:(BathRoom class)
private Lock lockW=new ReentrantLock();
public int women_present;
public BathRoom(){
women_present=0;//empty at start
}
public void woman_wants_to_enter (int i) {
lockW.lock();
women_present++;
System.out.println ("Woman " + i + " enters bathroom "); }
public void woman_leaves (int i) {
try {
Thread.sleep (1000);
}catch (InterruptedException e) {
e.printStackTrace();
}
System.out.println ("Woman " + i + " exits bathroom ");
if((women_present%3)==0){
women_present=0;
lockW.unlock();
} }
This is the Women class:
private int i; /* This identifies the woman. */
private BathRoom bathroom;
public Woman (BathRoom bathroom,int i) {
this.i = i;
this.bathroom = bathroom;
}
public void run () {
for (int i = 0; i < 3; i++) {
try {
Thread.sleep ((long) (500 * Math.random()));
}catch (InterruptedException e) {
e.printStackTrace();
}
bathroom.woman_wants_to_enter (i);
bathroom.woman_leaves (i);
}
}}
i took the liberty to modify your code :
package stackoverflow;
import java.util.concurrent.locks.Condition;
import java.util.concurrent.locks.Lock;
import java.util.concurrent.locks.ReentrantLock;
class BathRoom {
private Lock lockW=new ReentrantLock();
private Condition c1=lockW.newCondition();
public int women_present;
public BathRoom(){
women_present=0;//empty at start
}
public void woman_wants_to_enter (int i) {
lockW.lock();
while(women_present!=i)
try {
c1.await();
} catch (InterruptedException e) {
// TODO Auto-generated catch block
e.printStackTrace();
}
System.out.println ("Woman " + i + " enters bathroom "); }
public void woman_leaves (int i) {
try {
Thread.sleep (1000);
}catch (InterruptedException e) {
e.printStackTrace();
}
System.out.println ("Woman " + i + " exits bathroom ");
women_present++;
if(women_present==3){
women_present=0;
}
c1.signal();
lockW.unlock();
}
}
class Woman implements Runnable{
private int i; /* This identifies the woman. */
private BathRoom bathroom;
public Woman (BathRoom bathroom,int i) {
this.i = i;
this.bathroom = bathroom;
}
public void run () {
for (int i = 0; i < 3; i++) {
try {
Thread.sleep ((long) (500 * Math.random()));
}catch (InterruptedException e) {
e.printStackTrace();
}
bathroom.woman_wants_to_enter (i);
bathroom.woman_leaves (i);
}
}
}
public class testdummy {
public static void main(String[] args) {
BathRoom b=new BathRoom();
Woman w0=new Woman(b, 0);
Woman w1=new Woman(b, 1);
Woman w2=new Woman(b, 2);
Thread A=new Thread(w0);
Thread B=new Thread(w1);
Thread C=new Thread(w2);
A.start();
B.start();
C.start();
}
}
I have made use of Condition object to synchronize the thread access to the method , its not perfect but it works , hope it will give you thoughts for a better approach.
First thread
In woman_wants_to_enter(),
thread aquires lock() so continues.
woman_present is set to 1.
In woman_leaves(), woman_present is still 1
if (1 mod 3 is 1) so the unlock is not called
Second thread enters woman_wants_to_enter() but is waiting for the lock
Good afternoon everyone,
I am working on a school project that requires me to use semaphores to control access to resources. From what I have developed so far, they are:
Semaphore 1) Waiting Area - This permits only 15 customers (Threads) to enter the waiting area, else they are rejected from the store (using TryAcquire).
Semaphore 2) ServerQueue - This permits customers (Threads) to use the only 3 servers in the restaurant once in the waiting area.
My Problem: Our professor requires the serverQueue to take the shortest order (IE, the thread with the least amount of burritosOrdered) when in the waitingArea.
Full flow of application:
Main method instantiates a serverQueue (3 servers) and a waitingArea (15 customers)
Main method instantiates and starts 20 customer threads
Each customer (Thread) run function has been overridden to attempt to get in the waiting area
Each customer in the waitingArea tries to access a server in the serverQueue
How can I tell the serverQueue to get the shortest order? Because the threads override the run, I don't have direct access to an array of all the threads to compare their values.
Thank you for taking a look!
Main
public class Main {
private static final int numCustomers = 5;
public static void main(String[] args)
{
ServerQueue serverQueue = new ServerQueue();
WaitingArea waitingArea = new WaitingArea(3, serverQueue);
Thread customers[] = new Thread[numCustomers];
for (int i = 0; i < numCustomers; i++)
{
customers[i] = new Thread(new Customer(waitingArea), "Customer " + i);
}
for (int i = 0; i < numCustomers; i++)
{
customers[i].start();
}
}
}
Customer
import java.util.Date;
import java.util.Random;
// Runnable is an interface that facilitates threads
public class Customer implements Runnable {
// The semaphore
// private ServerQueue serverQueue;
private WaitingArea waitingArea;
public int burritosOrdered;
public int burritosMade = 0;
// Constructor, allow semaphore to be passed/assigned
public Customer(WaitingArea waitingArea) {
this.waitingArea = waitingArea;
Random r = new Random();
this.burritosOrdered = r.nextInt(21);
}
public void setBurritosMade(int newBurritos) {
this.burritosMade += newBurritos;
}
// We must override the run function within Runnable
// The run function is called by threadObject.start();
#Override
public void run() {
waitingArea.seatCustomer(burritosOrdered);
}
}
waitingArea
import java.util.Date;
import java.util.concurrent.Semaphore;
public class WaitingArea {
private Semaphore semaphore;
private ServerQueue serverQueue;
private int maxCustomers;
public WaitingArea(int maxCustomers, ServerQueue serverQueue) {
semaphore = new Semaphore(maxCustomers, true);
this.serverQueue = serverQueue;
this.maxCustomers = maxCustomers;
}
public void seatCustomer(int burritosOrdered)
{
boolean hasPermit = false;
try
{
hasPermit = semaphore.tryAcquire();
if(hasPermit) {
System.out.println(new Date() + " - "
+ Thread.currentThread().getName()
+ " entered store ordering "
+ burritosOrdered + " burritos");
serverQueue.finishOrder();
} else {
System.out.println(new Date() + " - " + Thread.currentThread().getName() + " left due to full shop");
}
} catch (InterruptedException e) {
e.printStackTrace();
} finally {
if(hasPermit) {
semaphore.release();
System.out.println(new Date() + " - "
+ Thread.currentThread().getName()
+ " left with " + burritosOrdered + " burritos made");
}
}
}
}
serverQueue
import java.util.Date;
import java.util.concurrent.Semaphore;
import java.util.concurrent.locks.Lock;
import java.util.concurrent.locks.ReentrantLock;
public class ServerQueue {
// This Semaphore will keep track of no. of servers used at any point.
private final Semaphore semaphore;
// While checking/acquiring a free server out of three available servers, we will use this lock.
private final Lock serverLock;
// This array represents the pool of free server.
private boolean freeServers[];
public ServerQueue() {
semaphore = new Semaphore(1, true);
freeServers = new boolean[1];
serverLock = new ReentrantLock();
// Set all servers to available
for(int i=0;i<freeServers.length;i++) {
freeServers[i] = true;
}
}
public void finishOrder() throws InterruptedException {
try {
System.out.println(semaphore.getClass());
// Decrease the semaphore counter to mark a printer busy
semaphore.acquire();
// Get the server printer
int assignedServer = getServer();
Thread.sleep(3000);
// Print the job
System.out.println(new Date() + " - " + Thread.currentThread().getName()
+ " is getting service from server " + assignedServer);
//Server is done; Free the server to be used by other threads.
releaseServer(assignedServer);
} catch (InterruptedException e) {
e.printStackTrace();
} finally {
System.out.print(new Date() + " - " + Thread.currentThread().getName() + " has been served\n");
//Increase the semaphore counter back
semaphore.release();
}
}
//Acquire a free server to finish a job
private int getServer() {
int foundServer = -1;
try {
//Get a lock here so that only one thread can go beyond this at a time
serverLock.lock();
//Check which server is free
for (int i=0; i<freeServers.length; i++)
{
//If free server found then mark it busy
if (freeServers[i])
{
foundServer = i;
freeServers[i] = false;
break;
}
}
} catch (Exception e) {
e.printStackTrace();
} finally {
//Allow other threads to check for free servers
serverLock.unlock();
}
return foundServer;
}
//Release the server
private void releaseServer(int i) {
serverLock.lock();
//Mark the server as free
freeServers[i] = true;
serverLock.unlock();
}
}
I have a program that simulates Gates to a ship. They run in threads. The idea is to let them run and pause during a random moment in the run method to simulate persons passing. This is done by all threads, meanwhile the main thread is waiting for notification and checking if the ship is getting full when notified by the threads that they added a person passing through the gate the main thread checks again if the ship is full. The program has three classes:
A counter:
public class Counter {
private int currentValue[];
private int maxValue;
public Counter(int[] nrOfPeople, int max) {
currentValue = nrOfPeople;
currentValue[0] = 0;
maxValue = max;
}
public synchronized void addPersons(int nr_p) {
currentValue[0] += nr_p;
}
public synchronized int getValue() {
return currentValue[0];
}
public synchronized boolean isFull() {
if(currentValue[0] < maxValue)
return false;
return true;
}
}
A Gate Class:
public abstract class Gate implements Runnable {
int nrOfPassengers;
int gatenr;
int gatesize;
Counter c;
private Thread t;
private Random r;
private boolean blocked; /* suspends people from passing */
public Gate(Counter c, int nr) {
this.c = c;
gatenr = nr;
this.open();
r = new Random();
t = new Thread(this);
t.start();
}
public void setGatesize(int size) {
gatesize = size;
}
public void close() {
blocked = true;
}
public void open() {
blocked = false;
}
public int getNoOfPassangers() {
return nrOfPassengers;
}
public int getId() {
return gatenr;
}
#Override
public void run() {
while(!blocked) {
int waitTime = (r.nextInt(5) + 1) * 1000; /* between 1-5 seconds */
System.out.println("Person-Gate " + gatenr + ": adding one to " + c.getValue());
try {
/* bigger throughput => amount can vary */
if(gatesize > 1) {
int persons = r.nextInt(gatesize)+1;
c.addPersons(persons);
nrOfPassengers += persons;
} else {
c.addPersons(1);
nrOfPassengers++;
}
Thread.sleep(waitTime);
} catch (InterruptedException e) {
System.out.println("Person-Gate " + gatenr + ": was interrupted adding person");
e.printStackTrace();
}
System.out.println("Person-Gate " + gatenr + ": added one to " + c.getValue());
t.notify();
}
}
public void join() {
try {
t.join();
} catch (InterruptedException e) {
e.printStackTrace();
}
}
}
And a Simulator that runs the main method:
/*
* This class simulates cars and persons- entering a ferry.
*/
public class Simulator {
public static final int MAX = 30;
public static void main(String[] args) {
int nrOfPeople[] = new int[1]; /* array of size one for keeping count */
ArrayList<Gate> gates = new ArrayList<Gate>();
Counter counter = new Counter(nrOfPeople, MAX);
Thread mainThread = Thread.currentThread();
/* adding 3 person-gates */
for(int i=1; i<4; i++) {
gates.add(new PersonGate(counter, i));
}
/* let all gates work as long as passengers is under MAX */
while(!counter.isFull()) {
try {
mainThread.wait();
} catch (InterruptedException e) {
// TODO Auto-generated catch block
e.printStackTrace();
}
}
System.out.println("Announcement: Ship is full!");
/* wait for child threads to finish */
for(Gate g: gates) {
g.close();
try {
g.join();
} catch (Exception e) { /* InterruptedException */
e.printStackTrace();
}
System.out.println(g.getNoOfPassangers() + " passed through gate nr " + g.getId());
System.out.println(counter.getValue() + " has passed in total");
}
}
}
Im getting a error
Person-Gate 1: adding one to 0
Person-Gate 2: adding one to 1
Person-Gate 3: adding one to 2
Exception in thread "main" java.lang.IllegalMonitorStateException
at java.lang.Object.wait(Native Method)
at java.lang.Object.wait(Object.java:485)
at Simulator.main(Simulator.java:24)
Person-Gate 3: added one to 3Exception in thread "Thread-3"
Does anyone now whats going on?
You can only call wait and notify/notifyAll from within synchronized blocks.
t.notify();
You are notifying wrong monitor. This exception occurs, when you do not wrap monitor object with synchronize section. However, objects which you are using for notify and for wait methods are different. Create new Object() monitor and pass it to the constructor of Gate.
Also you can take a look at CountDownLatch, it does exactly what you are trying to achieve.
You must own the monitor of the object on which you call wait or notify. Meaning, you must be in a synchonize-Block, like
synchronized( objectUsedAsSynchronizer) {
while ( mustStillWait) {
objectUsedAsSynchronizer.wait();
}
}
This has been the subject of many other questions.