3

I am new to multithreading. I am trying to write a program where I have two threads. One thread prints odd number and then gives up the monitor lock using wait() and similarly other thread prints the even number and gives up the lock after printing the number
I have got 4 classes

  1. Odd.java (print odd numbers between 1-100)
  2. Even.java(print even number between 1-100)
  3. SomeMaths.java( has got logic for printing odd and even numbers )
  4. OEApp.java (Main class that starts the threads)

Problem - My code works as expected most of the times i.e it print number 1 to 100 in order. Both the thread take turns. But I noticed that there is a bug.Sometimes the even thread gets scheduled first and gets below output

2    **********
1    ###############################

After that nothing gets printed, Looks like there is a deadlock situation. I am not able to figure out why. Please help me to understand this

public class SomeMaths {

    public synchronized void printOdd(){
        for( int i=1;i<=100;i++){
            if(i%2 !=0) {
                System.out.println(i + "       ###############################");
                try {
                    wait();
                } catch (InterruptedException e) {
                    e.printStackTrace();
                }
            }
            notify();
        }
    }

    public synchronized void printEven(){
        for(int i=1;i<=100;i++){
            if(i%2 ==0){
                System.out.println(i +"    **********");
                try {
                    wait();
                } catch (InterruptedException e) {
                    e.printStackTrace();
                }
            }
            notify();
        }
    }
  }

public class Odd implements Runnable {

    SomeMaths sm;

    public Odd(SomeMaths sm){
        this.sm = sm;
    }
    @Override
    public void run(){
       sm.printOdd();
    }
}

public class Even extends Thread {

    SomeMaths sm;

    public Even(SomeMaths sm){
        this.sm = sm;
    }

    @Override
    public void run(){
        sm.printEven();
    }
}

public class OEApp {

    public static void main(String[] args) {

        SomeMaths sm = new SomeMaths();

        Thread odd = new Thread(new Odd(sm));
        Thread even = new Thread(new Even(sm));

        odd.start();
        even.start();

        try {
            odd.join();
            even.join();
        } catch (InterruptedException e) {
            e.printStackTrace();
        }
    }
}
Hovercraft Full Of Eels
  • 283,665
  • 25
  • 256
  • 373
Jehan
  • 43
  • 2
  • *Curious:* If `Even` extends `Thread`, why do you wrapper it with another thread using `new Thread(new Even(sm))`? – Andreas Jul 29 '17 at 15:18

2 Answers2

6

I believe it works this way:

  1. Even thread starts, 1 is odd so it calls notify (notifying no one), then 2 is even so it prints a message and waits

  2. Odd thread starts, 1 is odd so it prints a message and waits

  3. There's no one to call notify so both threads wait forever

TomekK
  • 403
  • 1
  • 4
  • 11
  • I was about to ask what the solution is, but then realized question doesn't ask for solution, only explanation of why, so +1 from me. – Andreas Jul 29 '17 at 15:22
-2

What is your purpose for using the synchronize keyword ?
It can only assure you that your function will not be running multiple times at the same time.

I assume that you want one thread to notify another ? Is that right ?
But what if the notify is called before the wait occurred ?

You know that you can use the debugger to see each thread, and thus know where each thread is stuck ?

Please keep in mind, once start is called, you can't know which thread will have cpu time.

Furthermore you are trying to synchronize two threads (by the use of the notify/wait mecanism), but there are other mecanisms that will be proved simpler (e.g. semaphore: each thread having it own semaphore, acquiring it own semaphore and releasing the other one semaphore; initialize each semaphore to 1 and it will go smoothly).

P.S. :

lemmel
  • 132
  • 1
  • 6
  • 1
    *"What is your purpose for using the synchronize keyword ?"* For one, it's required when using `notify()` and `wait()`, so that's a dumb question. – Andreas Jul 29 '17 at 15:25
  • *"Why use both runnable and thread interface ?"* Because it is recommended to implement `Runnable` rather than extending `Thread`, which means you'll "use" both in the code. See [“implements Runnable” vs. “extends Thread”](https://stackoverflow.com/q/541487/5221149). – Andreas Jul 29 '17 at 15:30
  • Your comment about "Why use both runnable and thread interface ?" is a bit strange: I didn't advised to use either of them, but asked to the reason to use both of them. – lemmel Jul 29 '17 at 15:37
  • And the comment answered that: Because it is *recommended* to implement `Runnable` and then give that as parameter to the `Thread` constructor, i.e. you will *use* both. – Andreas Jul 29 '17 at 15:38
  • Agreed that Runnable is the best way to go but as I mentioned I am new to Threads, I was just playing around with both the approaches. – Jehan Jul 29 '17 at 15:39
  • It is recommanded to use both runnable and thread at the same time ? A source ? – lemmel Jul 29 '17 at 15:39
  • +1 for Producer-consumer and semaphores, this problem can be solved with 2 monitors and a flag but it's much easier to solve with semaphores. The answer is actually mostly good, looks like you forgot how monitors work, you admitted your mistake in the comments but didn't fix the answer. Another problem with your answer is that it's debatable if it actually answers the question. I think that if the OP will read and understand the Wikipedia link it will greatly help him "to understand this" so I say it does answer the question. – Oleg Jul 29 '17 at 23:16
  • @Andreas *Curious:* It's clear that he meant to ask him why he implemented `Runnable` in one case **and** extended `Thread` in the second case. What did you think he meant and why did you argue with him about it? – Oleg Jul 30 '17 at 00:32
  • @Oleg I had already [commented to OP](https://stackoverflow.com/questions/45390716/java-code-threads-blocking-each-other/45390896?noredirect=1#comment77742296_45390716) about that, and the way it's phrased here ("Why use both runnable and thread interface ?"), it is certainly not *clear* that that is what is being referring to, since `new Thread(myRunnable)` is also a use of both, hence my comment with link to why you should use `Thread` with `Runnable`, rather than just extending `Thread`. – Andreas Jul 30 '17 at 00:49
  • @Jehan Actually don't read that Wikipedia article. It's usually a good source for relatively simple technical stuff butt in this case they have a race condition in their monitor(java's synchronized) implementation which can cause a deadlock. – Oleg Jul 30 '17 at 01:49
  • @Andreas Oleg and lemmel - Guys , I appreciate all the suggestions provided by you and thanks for taking time to help me. Lets keep it friendly and yes I am fortunate to be the member of this community. You guys are the best – Jehan Jul 30 '17 at 05:18