I'm just starting to learn multithreading.
Notify does not work in the unlock method. Elements that are included in the wait, do not come out of waiting.
public class Tunnel {
static AtomicInteger limit = new AtomicInteger(0);
static boolean isOpen = false;
void goIntoTunnel() throws InterruptedException {
lock();
int timeIntoTunnel = (int) (Math.random() * 5000);
System.out.println(Thread.currentThread().getName() + " go into the tunnel");
Thread.sleep(timeIntoTunnel);
unlock();
System.out.println(Thread.currentThread().getName() + " left the tunnel, time: " + timeIntoTunnel);
}
void lock() throws InterruptedException {
synchronized (this) {
if (limit.get() < 3) {
limit.incrementAndGet();
} else isOpen = true;
while (isOpen) {
wait();
}
}
}
void unlock() throws InterruptedException {
synchronized (this) {
limit.getAndSet(limit.get()-1);
isOpen = false;
notify();
}
}
}
Simulation of the race. Cars enter the tunnel, and there cannot be more than 3 cars in the tunnel at the same time
Your code works fine on my machine.
The testing code:
The output:
I don't see anything in the code of
Tunnelthat might prevent waiting threads from waking up:notify()in the end, this wakes up one waiting thread (if there are any)notify(), this wakes up another waiting threadThe only thing I can think of is if this
Tunnelobject is also used somewhere else in your code for waiting.In this case
notify()inunlock()might wake up that other waiting thread instead of one of the waiting car-threads.P.S. There are some additional problems in your code:
limitis not incremented insidelock()when the thread is awoken. This might lead to 4 cars (3 threads that didn't wait + 1 awoken thread) in the tunnel simultaneously.Tunnel.isOpenistruewhen the tunnel is closed, and isfalsewhen the tunnel is closed. That's counter-intuitive.AtomicIntegerbyint, because in your code it's used only insidesynchronizedblocks. And code likelimit.getAndSet(limit.get()-1)defeats the purpose of theAtomicInteger's existence.