1

I'm trying to print numbers 1-20 with two threads:

  • Even thread - Print only even numbers.
  • Odd thread - print only odd numbers.

I also have a lock object for synchronization.

My application is stuck. Can you tell me what is the problem?

My code:

public class runIt
{

    public static void main(String[] args)
    {
        Odd odd = new Odd("odd thread");
        Even even = new Even("even thread");

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

        try{
            odd._t.join();
            even._t.join();
        }
        catch (InterruptedException e){
            System.out.println(e.getMessage());
        }   
    }
}

public class Constants{
    static Object lock = new Object();
}

public class Even implements Runnable{
    Thread  _t;
    String  _threadName;

    public Even(String threadName){
        _threadName = threadName;
        _t = new Thread(this);
    }

    @Override
    public void run(){
        for (int i = 0; i < 20; i++){
            if (i % 2 == 0){
                synchronized (Constants.lock){                  
                    try{
                        Constants.lock.wait();
                        Constants.lock.notifyAll();
                    }
                    catch (InterruptedException e){
                        e.printStackTrace();
                    }
                    System.out.println(_threadName + " " + i + " ");
                }
            }
        }
    }
}

public class Odd implements Runnable{
    Thread  _t;
    String  _threadName;

    public Odd(String threadName){
        _threadName = threadName;
        _t = new Thread(this);

    }

    @Override
    public void run(){
        for (int i = 0; i < 20; i++){
            if (i % 2 == 1){
                synchronized (Constants.lock){                  
                    try{
                        Constants.lock.wait();
                        Constants.lock.notifyAll();
                    }
                    catch (InterruptedException e1){
                        e1.printStackTrace();
                    }
                    System.out.println(_threadName + " " + i + " ");
                }
            }
        }
    }
}

My output should be:

1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20

Thank you for the assistance, Tam.

akash
  • 22,664
  • 11
  • 59
  • 87
TamK
  • 19
  • 1
  • 2
  • Take a look here: http://stackoverflow.com/questions/6017281/odd-even-number-printing-using-thread It seems to be exactly what you need. – Adrian Olar Jul 13 '14 at 08:32
  • 10
    So I guess this means somewhere a new semester just started? *sigh* – Voo Jul 13 '14 at 09:02
  • Your immediate issue is that both threads go into a wait on the lock, and then they never get notified. There are a few other issues with this code as well, though. – Warren Dew Jul 13 '14 at 09:20
  • @WarrenDew said, "there are a few other issues..." Here's one: You wrote `new Thread(this)` in your constructors. That may not be causing any problem for you in this code, but google for "leaking this in constructor" if you want to know why it's generally a Bad Idea. – Solomon Slow Jul 13 '14 at 17:33

6 Answers6

1

You are misusing synchronized and wait by calling wait on the object you used in synchronized, immediately, without having a check inside the synchronized block in a loop. NEVER DO THAT AGAIN.

In fact here's what happen :

  • at synchronized line you get a lock on Constants.lock
  • at wait line, you release the lock on Constants.lock and wait for a notify from another thread.

So what is happening in your prog :

  • first thread (no matter what it is) reaches synchronized and proceed blocking the second
  • first thread releases the synchonizing lock and put itself in a wait state for a notify
  • second thread goes through synchronized because first has released the lock
  • both thread are now waiting for a notify that will never occur
Nathan Hughes
  • 94,330
  • 19
  • 181
  • 276
Serge Ballesta
  • 143,923
  • 11
  • 122
  • 252
  • It is a rather old question, but I could remember what it was about. I said it should never be done again, because it is a recipe for building deadlocks... – Serge Ballesta Feb 25 '19 at 14:54
1

You can find the explanation in the site mentioned in package declaraion: Here's the working code:

public class MultipleThreading {
    int count = 1;
    int MAX = 20;

    public void printOdd() {
    synchronized (this) {
        while (count < MAX) {
        while (count % 2 == 0) {
            try {
            wait();
            } catch (InterruptedException e) {
            e.printStackTrace();
            }
        }
        System.out.print(count + " ");
        count++;
        notify();
        }
    }
    }

    public void printEven() {
    synchronized (this) {
        while (count < MAX) {
        while (count % 2 == 1) {
            try {
            wait();
            } catch (InterruptedException e) {
            e.printStackTrace();
            }
        }
        System.out.print(count + " ");
        count++;
        notify();
        }
    }
    }

    public static void main(String[] args) {
    MultipleThreading mt = new MultipleThreading();
    Thread t1 = new Thread(new Runnable() {
        @Override
        public void run() {
        mt.printEven();
        }
    });
    Thread t2 = new Thread(new Runnable() {
        @Override
        public void run() {
        mt.printOdd();
        }
    });
    t1.start();
    t2.start();
    }
}
v0ld3m0rt
  • 866
  • 3
  • 12
  • 47
0

Below code will help to someone,

public class MyClass {

private static Object lock = new Object();

public static void main(String args[]){

    Runnable runnable1 = new Runnable() {
        @Override
        public void run() {
            for(int i=1; i<20; i=i+2){
                synchronized (lock) {
                    System.out.println("Thread 1: "+i);
                    try {
                        lock.notifyAll();
                        lock.wait();
                    } catch (InterruptedException e) {
                        System.out.println("Error in Thread 1: "+e.getMessage());
                    }
                }
            }
        }
    };


    Runnable runnable2 = new Runnable() {
        @Override
        public void run() {
            for(int i=2; i<=20; i=i+2){
                synchronized (lock) {
                    System.out.println("Thread 2: "+i);
                    try {
                        lock.notifyAll();
                        lock.wait();
                    } catch (InterruptedException e) {
                        System.out.println("Error in Thread 2: "+e.getMessage());
                    }
                }
            }
        }
    };

    Thread thread1 = new Thread(runnable1);
    Thread thread2 = new Thread(runnable2);

    System.out.println("Thread Start: ");
    thread1.start();
    thread2.start();               
}

}
Thirumalvalavan
  • 2,660
  • 1
  • 30
  • 32
0

Everyone on the Stack Overflow tried the same solution. Checkout a different implementation for the same.

public class PrintSequenceUsingTwo {

    public static void main(String[] args) {
        ThreadSequence sequence = new ThreadSequence();
        Thread t1 = new Thread(()-> {try {
            sequence.print();
        } catch (InterruptedException e) {
            e.printStackTrace();
        }},"t1");
        Thread t2 = new Thread(()-> {try {
            sequence.print();
        } catch (InterruptedException e) {
            e.printStackTrace();
        }},"t2");

        t1.start();
        t2.start();
        try {
            t1.join();
            t2.join();
        } catch (Exception e) {
            e.printStackTrace();
        }
    }
}

class ThreadSequence {

    private static int var = 0; 
    private int limit = 10;     //set the variable value upto which you want to print

    public synchronized void print() throws InterruptedException {
        while (var<limit) {
            notify();
            System.out.println("Current Thread "+Thread.currentThread().getName()+" Value : "+(++var));
            wait();
        }
        notify();
    }
}
Suraj Rao
  • 29,388
  • 11
  • 94
  • 103
0
public class Print1To20 {

    int couter=0;
    static int N;

    public void preven(){
        synchronized (this) {
            while(couter<N) {
                while(couter%2==0) {
                    try {
                        wait();
                    } catch(Exception e) {
                    }
                    System.out.println(Thread.currentThread().getName()+":"+couter);
                }
                couter++;
                notify();
            }
        }
    }
    public void prodd(){
        synchronized (this) {
            while(couter<N) {
                while(couter%2==1) {
                    try {
                        wait();
                    } catch(Exception e) {
                    }
                    System.out.println(Thread.currentThread().getName()+":"+couter);
                }
                couter++;
                notify();
            }
        }
    }
    
    public static void main(String[] args) {
        // TODO Auto-generated method stub

        //  Thread t1= new Th;

        //Thread t2= new Thread(new PrintOdd());

        N=20;
        Print1To20 pt= new Print1To20();
        Thread t1= new Thread(new Runnable() {
            @Override
            public void run() {
                // TODO Auto-generated method stub
                pt.preven();
            }
        });

        Thread t2= new Thread(new Runnable() {
            @Override
            public void run() {
                // TODO Auto-generated method stub
                pt.prodd();
            }
        });
        t1.start();
        t2.start();
    }
}

Ref: Reference taken from GeekforGeeks

Tom Taylor
  • 3,344
  • 2
  • 38
  • 63
0
Try this solution.....

public class Print1To20Using2Thread {
    public static void main(String[] args) {
        PrintNumber pn = new PrintNumber(new Object());
        Thread t1 = new Thread(pn, "First");
        Thread t2 = new Thread(pn, "Second");

        t1.start();
        t2.start();
    }
}

class PrintNumber implements Runnable {

    Object lock;
    int i = 0;
    public PrintNumber(Object lock) {
        this.lock = lock;
    }

    @Override
    public void run() {
        synchronized (lock) {
            for (; i <= 20; i++) {
                if (i == 11) {
                    try {
                        lock.wait(1000);
                    } catch (InterruptedException e) {
                        e.printStackTrace();
                    }
                }
                System.out.print(" "+Thread.currentThread().getName() + " " + i);
                lock.notifyAll();
            }
            System.out.println();
        }
    }
}