2

I was attempting to solve a multi threaded problem and I am facing difficulties getting to know its behavior.

The problem is: There are 2 threads which simultaneously consume even and odd numbers. I have to introduce the thread communication between them to have the "consumption" in natural ordering.

here is my code

public class EvenOddDemo {

    public static void main(String[] args) {
        Number n = new Number();
        EvenThread et = new EvenThread(n);
        OddThread ot = new OddThread(n);
        et.start();
        ot.start();
    }

}

class EvenThread extends Thread {

    private Number number;

    public EvenThread(Number number) {
        this.number = number;
    }

    @Override
    public void run() {
        for(int i=0; i<5; i++) {
            System.out.println(number.getEven());
        }
    }


}

class OddThread extends Thread {

    private Number number;

    public OddThread(Number number) {
        this.number = number;
    }

    @Override
    public void run() {
        for(int i=0; i<5; i++) {
            System.out.println(number.getOdd());
        }
    }


}

class Number {

    private int currentEven = 0;

    private int currentOdd = 1;

    private volatile String last = "odd";

    public synchronized int getEven() {
        if("even".equals(last)) {
            try {
                wait();
            } catch (InterruptedException e) {
                e.printStackTrace();
            }
        }
        int i = currentEven;
        last = "even";
        currentEven +=2;
        notify();
        return i;
    }

    public synchronized int getOdd() {
        if("odd".equals(last)) {
            try {
                wait();
            } catch (InterruptedException e) {
                e.printStackTrace();
            }
        }
        int i = currentOdd;
        last = "odd";
        currentOdd +=2;
        notify();
        return i;
    }
}

and the output is

0
2
1
3
4
5
7
6
8
9

But when I debug the code, it prints the numbers in the correct order. Hence I am not able to figure out what I am missing. Please help me. Thanks in advance for your time for this thread.

sanbhat
  • 17,522
  • 6
  • 48
  • 64
  • 1
    There are *numerous* dups of this homework on SO. Here's one: http://stackoverflow.com/questions/6017281/odd-even-number-printing-using-thread?rq=1 and another http://stackoverflow.com/questions/16689449/printing-even-and-odd-using-two-threads-in-java?rq=1 – Brian Roach Jul 12 '13 at 17:52
  • @BrianRoach Thanks for your comment. However I am doing `notify` and `wait` on same `Number` instance.. so how its not working for me? – sanbhat Jul 12 '13 at 17:54
  • 2
    Just for the record, debugging multi threaded applications aren't guaranteed to behave as you expect, it might give you the right results once (or maybe always) and never shown the real problems. – Luiggi Mendoza Jul 12 '13 at 17:55
  • 1
    @BrianRoach Although to be honest I'm not sure why his code (which is very similar to the answers you point to) does not work. – assylias Jul 12 '13 at 17:55

3 Answers3

5

As far as I can see, there is nothing preventing this from happening, explaining why 2 is displayed before 1 in your output:

OddThread     EvenThread
----------    ----------
gets odd
              gets even
              prints even
prints odd

The lock therefore needs to be around the whole sequence "get/print".

You'll notice that you are never "two numbers apart" in your output, too.

fge
  • 119,121
  • 33
  • 254
  • 329
  • 1
    That's exactly the problem - I was scratching my head (and using notifyAll + calling wait in a loop would be a good idea). – assylias Jul 12 '13 at 18:06
  • Thanks a lot.. I added the print statement in `getOdd`, `getEven` methods and it worked perfectly! – sanbhat Jul 12 '13 at 18:07
2

notify chooses any available thread.

The choice is arbitrary and occurs at the discretion of the implementation

If there are more than two threads waiting you could be signalling the "wrong" thread.

Also, note that both of your threads could be just finished in get(Even|Odd) with neither waiting, leading to the notify going nowhere depending upon the scheduling.

You need to be more strict to ensure the ordering. Perhaps two locks, even and odd, would be helpful.

Paul Rubel
  • 26,632
  • 7
  • 60
  • 80
0

You need to print the number in getEven and getOdd functions and notify the other thread. But you were notifying and printing the number, so between noti Modified code:

public class ThreadExp {

    public static void main(String[] args) {
        Number n = new Number();
        EvenThread et = new EvenThread(n);
        OddThread ot = new OddThread(n);
        et.start();
        ot.start();
    }

}

class EvenThread extends Thread {

    private Number number;

    public EvenThread(Number number) {
        this.number = number;
    }

    @Override
    public void run() {
        for (int i = 0; i < 10; i++) {
            number.getEven();
        }
    }

}

class OddThread extends Thread {

    private Number number;

    public OddThread(Number number) {
        this.number = number;
    }

    @Override
    public void run() {
        for (int i = 0; i < 10; i++) {
            number.getOdd();
        }
    }

}

class Number {

    private int currentEven = 0;

    private int currentOdd = 1;

     private StringBuilder odd;
     private StringBuilder even;
     private StringBuilder last;

    {
        odd = new StringBuilder("odd");
        even = new StringBuilder("even");
        last = odd;
    }

    public synchronized void getEven() {
        if (last == even) {
            try {
                 //System.out.println("inside if in even--->" +Thread.currentThread());
                wait();
            } catch (InterruptedException e) {
                e.printStackTrace();
            }
        }
        //System.out.println("out of if in even--> " + Thread.currentThread());
        int i = currentEven;
        last = even;
        currentEven += 2;
        System.out.println(i);
        notify();
        return;
    }

    public synchronized void getOdd() {
        if (last == odd) {
            try {
                //System.out.println("inside if in odd--->" +Thread.currentThread());
                wait();
            } catch (InterruptedException e) {
                e.printStackTrace();
            }
        }
        //System.out.println("out of if in odd--> " + Thread.currentThread());

        int i = currentOdd;
        last = odd;
        currentOdd += 2;
        System.out.println(i);
        notify();
        return;
    }
}
user848066
  • 63
  • 7