-1

I have two very similar programs each trying to run two threads OddThread and EvenThread and trying to print the odd and even numbers in sequence . While the first one works , the second one hangs . Can anyone please pinpoint the bug in the second program ?

The first one which works :

public class ThreadTest {

public static void main(String[] args) {
    System.out.println("Odd Even test");
    NumHolder objNumHolder = new NumHolder();
    Odd o1 = new Odd(objNumHolder, "Odd Number Thread");
    Even e1 = new Even(objNumHolder, "Even Number Thread");
    o1.start();
    e1.start();
}
}

class NumHolder {
private int intCurrNum;
private boolean isEven = false;

public synchronized void printOddNumber(String tname) {
    while (isEven == true){
        try {
            wait();
        }catch (InterruptedException e) {
        }
    }
    isEven = true;
    System.out.println("Thread Name="+tname + "===Number="+intCurrNum);
    intCurrNum += 1;
    notifyAll();
}

public synchronized void printEvenNumber(String tname) {
    while (isEven == false) {
        try {
            wait();
        } catch (InterruptedException e) {
        }
    }
    isEven = false;
    System.out.println("Thread Name="+tname + "===Number="+intCurrNum);
    intCurrNum += 1;
    notifyAll();
}
}

class Even extends Thread {
private NumHolder objNumHolder;

public Even(NumHolder p_objNumHolder, String name) {
    super(name);
    objNumHolder=p_objNumHolder;
}

public void run() {
    for (int i = 0; i < 10; i++) {
        objNumHolder.printEvenNumber(getName());
    }
}
}
class Odd extends Thread {
private NumHolder objNumHolder;

public Odd(NumHolder p_objNumHolder,String name) {
    super(name);
    objNumHolder = p_objNumHolder;
}

public void run() {
    for (int i = 0; i < 10; i++) {
        objNumHolder.printOddNumber(getName());
    }
}
}

The second code which hangs :

class PrintClass {
int intCurrNum;
private boolean isEven = false;

synchronized void printOdd(){
    while(isEven){
        try{
            wait();
        }catch(InterruptedException ie){
            System.out.println("Interrupted exception in printOdd()");
            ie.printStackTrace();
        }
        isEven = true;
        System.out.println("Thread Name="+Thread.currentThread().getName() + "===Number="+intCurrNum);
        intCurrNum += 1;
        notifyAll();
    }
}

synchronized void printEven(){
    while(!isEven){
        try{
            wait();
        }catch(InterruptedException ie){
            System.out.println("Interrupted exception in printEven()");
            ie.printStackTrace();
        }
        isEven = false;
        System.out.println("Thread Name="+Thread.currentThread().getName() + "===Number="+intCurrNum);
        intCurrNum += 1;
        notifyAll();
    }
}
}
class ThreadOdd extends Thread {
PrintClass pc = null;

ThreadOdd(PrintClass pc , String name){
    super(name);
    this.pc = pc;
}

public void run(){
    for (int i = 0; i < 10; i++) {
        pc.printOdd();
    }
}
}
class ThreadEven extends Thread {
PrintClass pc = null;

ThreadEven(PrintClass pc,String name){
    super(name);
    this.pc = pc;
}

public void run(){
    for (int i = 0; i < 10; i++) {
        pc.printEven();
    }
}
}
public class EvenOddPrintClass {
public static void main(String[] args){
    PrintClass pc = new PrintClass();
    Thread to = new ThreadOdd(pc,"ThreadOdd");
    Thread te = new ThreadEven(pc,"ThreadEven");
    to.start();
    te.start();
}
}

Thanks.

AllTooSir
  • 48,828
  • 16
  • 130
  • 164
  • Is this homework related? If one thread is "hanging", it's probably because your first thread has locked a resource which the second thread is trying to acquire a lock on; alternately, it could be waiting for a signal, but thread one never gives the signal. We need to know what's inside the `wait` function, otherwise it's difficult to tell. – Kiril Mar 22 '12 at 18:57
  • @Lirik: It's the wait-method from java.lang.Object. The other thread keeps on waiting for the other thread to wake it with the notifyAll -calls at the end of the printOdd/printEven -methods, but probably they'll get stuck at either the method synchronization or the other thread falls through from the while-loop and other is stuck wait():in for the notify. – esaj Mar 22 '12 at 19:00
  • @esaj... oh, got it. I forgot about that! – Kiril Mar 22 '12 at 19:03

4 Answers4

0

Interesting. So initially the isEven = false. If the printOdd() is called first then the while (isEven) test is false so printOdd() will exit immediately without generating any output. The while loops in your first program only encompass the wait test, not the entire method.

Then when printEven() is called by the other thread, it will call wait() and hang since there is no other thread to call notifyAll().

You only should want the while loop around the wait since you are going to exit after you print out the even or odd number anyway, right? So the logic in the first program is correct.

Gray
  • 115,027
  • 24
  • 293
  • 354
0

In both versions, isEven starts out as false.

In the first version, printOddNumber will skip the whole while loop, print the odd number, set isEven to true and notify the even thread, which will print the even number and notify the odd thread again etc. in sequence.

In the second version, printOddNumber will skip the whole while loop, including printing the number and notifying the even thread. After 10 attempts it will exit without having printed anything, and leaving the even thread hanging without ever having notified it.

Joachim Isaksson
  • 176,943
  • 25
  • 281
  • 294
0

I suggest you run your code in the debugger and step through both threads. It's very educational. You will see exactly where the error is.

Pavel Rozenblioum
  • 144
  • 1
  • 2
  • 5
0
public class CountDownApp
 {
 public static void main(String[] args)
 {
 Thread count1 = new CountDownEven();
 Thread count2 = new CountDownOdd();
 count1.start();
 count2.start();

 }
 }

 class CountDownEven extends Thread
 {
 public void run()
 {
 for(int i=10;i>0;i-=2)
 { 
 System.out.print(+i+"-");

 try {
    Thread.sleep(2);
} catch (InterruptedException e) {
    // TODO Auto-generated catch block
    e.printStackTrace();
}
 }
 }

 }

 class CountDownOdd extends Thread 
 {
 public void run()
 {
 for(int i=9;i>0;i-=2)
 {
 System.out.print(+i+"-");

 try {
        Thread.sleep(2);
    } catch (InterruptedException e) {
        // TODO Auto-generated catch block
        e.printStackTrace();
    }
 }
 }

 }
Raj
  • 1