Each thread has its own path of execution through the code. Even if two threads run the exact same code they still have two distinct execution points through the code execution through the code. When a thread reaches a synchronized statement it waits for the lock to be available - it will enter the synchronized block only if no other thread is inside a synchronized block guarded by the same lock.
You keep getting the same output although you removed the notify/wait statements can be coincidental. Did you try this with a relatively large value of the
count
field?It is kind of hard to answer this question at the moment as you didn't specify what output do you expect this program to produce. Is "1,3,5,7,9,2,4,6,8" a valid output? Is "1,3,2,4,6,5,7,9,8"? Or is "1,2,3,4,5,6,7,8,9" the only valid output? That said, here a few quick points:
Use notifyAll() instead of notify
Minimize the state that is shared between threads. In this case, you share both
isOdd
andc
. Note that the former can be computed from the latter viac % 2 == 1
. Thus you can have the thread computing oddness instead of maintaining it as a piece of shared data.Instead of sharing via static fields create an object (with instance fields) and pass this object to the constructor of each thread. Then you can use the object itself as a lock.
Here's how it can look like:
class SharedData {
int c;
boolean isOdd;
}
class ThreadEvenOdd {
SharedData sharedData;
public ThreadEvenOdd(SharedData sd) { this.sharedData = sd }
// ...
void printOdd(int count) {
try {
for(int i=0;i<count/2;i++) {
synchronized(sharedData) {
if(!sharedData.isOdd) { ... }
System.out.println(sharedData.c);
sharedData.c++;
sharedData.isOdd = false;
lock.notify();
}
}
}
catch(Exception e) {
System.out.println(e);
}
}
}
The nice thing about it is that you can then start defining real methods on sharedData (such as: a method that increases c
and set isOdd
to the appropriate value based on the value of c
thus further simplifying the code in the thread class - and making the synchronization/notification less interleaved with the processing of the data, which makes the code more readable and less prone to errors.