public class ThreadA {
public static void main(String[] args){
ThreadB b = new ThreadB();
b.start();
synchronized(b){
try{
You should almost always have a predicate together with wait/notify. That is, you need a condition that you can check, such as a variable becoming true, a queue becoming empty/full etc. Just blindly waiting for someone to call .notify() have very few use cases.
So, The following is Not OK, for the reason you say, the other thread could call .notify() before ThreadA calls .wait()
public class ThreadA {
public static Object latch = new Object();
public static void main(String[] args) {
ThreadB b = new ThreadB();
b.start();
synchronized(latch ) {
latch.wait(); //wait for B to finish a calculation
}
System.out.println("Total is: " + b.total);
}
}
class ThreadB extends Thread {
int total;
@Override
public void run() {
for (int i = 0; i < 100; i++) {
total += i;
}
synchronized(ThreadA.latch) {
ThreadA.latch.notify();
}
}
}
You need to do something like this:
public class ThreadA {
public static Object latch = new Object();
public static boolean done = false;
public static void main(String[] args) {
ThreadB b = new ThreadB();
b.start();
synchronized(latch ) {
while (!done) { //wait for B to indicate it is finished.
latch.wait();
}
}
System.out.println("Total is: " + b.total);
}
}
class ThreadB extends Thread {
int total;
@Override
public void run() {
for (int i = 0; i < 100; i++) {
total += i;
}
synchronized(ThreadA.latch) {
ThreadA.done = true;
ThreadA.latch.notify();
}
}
}
Note that in the above, the done
variable is protected by the synchronized block, .wait()
will atomically release/re-aquire that lock. So there is no race condition, and if .notify() is called before we get to the .wait()
call , ThreadA will discover that because done
will be true
and not enter the .wait()
call at all.
For a simple case such as this code, you can just wait for ThreadB to to end, can be done with b.join();
One of the many possible solutions for your problem is:
public class ThreadA {
public static final CyclicBarrier barrier = new CyclicBarrier(2);
public static void main(String[] args) {
ThreadB b = new ThreadB();
b.start();
try {
barrier.await();
System.out.println("Total is: " + b.total);
} catch (InterruptedException | BrokenBarrierException ex) {
}
}
}
class ThreadB extends Thread {
int total;
@Override
public void run() {
for (int i = 0; i < 100; i++) {
total += i;
}
try {
ThreadA.barrier.await();
} catch (InterruptedException | BrokenBarrierException ex) {
}
}
}
I guess you want to do something like this
public class ThreadA {
public static void main(String[] args) {
ThreadB b = new ThreadB();
b.start();
b.join(); // Wait for thread b to finish
System.out.println("Total is: " + b.total);
}
}
You should also let ThreadB only implement Runnable
and not extend Thread
.
class ThreadB implements Runnable {
int total;
public void run() {
for (int i = 0; i < 100; i++) {
total += i;
}
}
}
and then use it
ThreadB tb = new ThreadB();
Thread b = new Thread(tb);