I have 2 threads. One thread prints odd numbers and the second thread prints even numbers. Now, I have to execute the threads alternatively so that i can output 1,2,3,4,5,6,…..
I have written a program for this and this is resulting in a deadlock. Can someone explain what is the problem with the code and how to rectify it?
class BooleanObject {
boolean flag;
BooleanObject(boolean flag) {
this.flag = flag;
}
}
class EvenThread extends Thread {
Object lock;
BooleanObject flagObj;
EvenThread(Object o, BooleanObject flag) {
lock = o;
this.flagObj = flag;
}
public void run() {
for (int i=2;i<100;i+=2) {
synchronized(lock) {
if (flagObj.flag == false) {
flagObj.flag = true;
lock.notify();
}
else {
try {
while (flagObj.flag == true) {
lock.wait();
}
}
catch (InterruptedException e) {
}
}
System.out.println(i);
}
}
}
}
class OddThread extends Thread {
Object lock;
BooleanObject flagObj;
OddThread(Object o, BooleanObject flag) {
lock = o;
this.flagObj = flag;
}
public void run() {
for (int i=1;i<100;i+=2) {
synchronized(lock) {
if (flagObj.flag == true) {
flagObj.flag = false;
lock.notify();
}
else {
try {
while(flagObj.flag == false) {
lock.wait();
}
}
catch (InterruptedException e) {
}
}
System.out.println(i);
}
}
}
}
public class EvenOddThreads {
public static void main(String[] args) {
Object obj = new Object();
BooleanObject flagObj = new BooleanObject(true);
EvenThread et = new EvenThread(obj,flagObj);
OddThread ot = new OddThread(obj,flagObj);
et.setName("even thread");
ot.setName("odd thread");
et.start();
ot.start();
}
}
The problem is with auto-boxing. When you change
flagfrom true to false or vice versa, you are actually getting an entirely newBooleanobject. That is, this line:Is equivalent to:
Once that happens your two threads are then referring to two different
Booleanobjects, so their flags end up un-synchronized and neither thread is able to signal the other to wake up. WhenOddThreadchanges the flagEvenThreadstill has the old flag object so it doesn’t see the new value.Because a
Booleanobject is immutable you’ll need to change your flag to use some other mutable object which can change values in place without creating new objects. That, or have both classes refer to a common (perhaps global) variable.As @erickson suggests you could use
AtomicBooleanwhich is mutable. Another kludgy way to do it would be to changeflagto:And then use
flag[0]every where. Both threads would then be able to changeflag[0]while always referencing the sameboolean[]array object. You wouldn’t have the auto-boxing problem.…
Also, it is a good idea to wrap any call to
wait()in a loop. Await()can be subject to spurious wakeups where the call returns even though nobody has actually callednotify(). To workaround that you should always check your guarding condition after waking up to make sure the wakeup isn’t spurious.Update
When you end up waiting, once you are woken up you don’t toggle
flagand notify the other thread. I advise reorganizing your code a bit so it looks like “wait; print; notify”. Something like: