Ravi Chandra
Ravi Chandra

Reputation: 687

Multi threaded java program to print even and odd numbers alternatively

I was asked to write a two-threaded Java program in an interview. In this program one thread should print even numbers and the other thread should print odd numbers alternatively.

Sample output:

Thread1: 1

Thread2: 2

Thread1: 3

Thread2: 4 ... and so on

I wrote the following program. One class Task which contains two methods to print even and odd numbers respectively. From main method, I created two threads to call these two methods. The interviewer asked me to improve it further, but I could not think of any improvement. Is there any better way to write the same program?

class Task
{
    boolean flag;

    public Task(boolean flag)
    {
        this.flag = flag;
    }
    public void printEven()
    {
        for( int i = 2; i <= 10; i+=2 )
        {
            synchronized (this)
            {
                try
                {
                    while( !flag )
                        wait();
                    System.out.println(i);
                    flag = false;
                    notify();
                }
                catch (InterruptedException ex)
                {
                    ex.printStackTrace();
                }
            }
        }
    }
    public void printOdd()
    {
        for( int i = 1; i < 10; i+=2 )
        {
            synchronized (this)
            {
                try
                {
                    while(flag )
                        wait();
                    System.out.println(i);
                    flag = true;
                    notify();
                }
                catch(InterruptedException ex)
                {
                    ex.printStackTrace();
                }
            }
        }
    }
}

public class App {
    public static void main(String [] args)
    {
        Task t = new Task(false);
        Thread t1 = new Thread( new Runnable() {
           public void run()
           {
               t.printOdd();
           }
        });
        Thread t2 = new Thread( new Runnable() {
            public void run()
            {
                t.printEven();
            }
        });
        t1.start();
        t2.start();
    }
}

Upvotes: 3

Views: 1700

Answers (5)

Jukka
Jukka

Reputation: 4663

My initial answer was non-functional. Edited:

package test;

public final class App {

    private static volatile int counter = 1;
    private static final Object lock = new Object();

    public static void main(String... args) {
        for (int t = 0; t < 2; ++t) {
            final int oddOrEven = t;
            new Thread(new Runnable() {
                @Override public void run() {
                    while (counter < 100) {
                        synchronized (lock) {
                            if (counter % 2 == oddOrEven) {
                                System.out.println(counter++);
                            }
                        }
                    }
                }
            }).start();
        }
    }
}

Upvotes: 0

Evgeny Zhuravlev
Evgeny Zhuravlev

Reputation: 133

I think this should work properly and pretty simple.

package com.simple;

import java.util.concurrent.Semaphore;

/**
 * @author Evgeny Zhuravlev
 */
public class ConcurrentPing
{
    public static void main(String[] args) throws InterruptedException
    {
        Semaphore semaphore1 = new Semaphore(0, true);
        Semaphore semaphore2 = new Semaphore(0, true);
        new Thread(new Task("1", 1, semaphore1, semaphore2)).start();
        new Thread(new Task("2", 2, semaphore2, semaphore1)).start();
        semaphore1.release();
    }

    private static class Task implements Runnable
    {
        private String name;
        private long value;
        private Semaphore semaphore1;
        private Semaphore semaphore2;

        public Task(String name, long value, Semaphore semaphore1, Semaphore semaphore2)
        {
            this.name = name;
            this.value = value;
            this.semaphore1 = semaphore1;
            this.semaphore2 = semaphore2;
        }

        @Override
        public void run()
        {
            while (true)
            {
                try
                {
                    semaphore1.acquire();
                    System.out.println(name + ": " + value);
                    value += 2;
                    semaphore2.release();
                }
                catch (InterruptedException e)
                {
                    throw new RuntimeException(e);
                }
            }
        }
    }

}

Upvotes: 2

Solomon Slow
Solomon Slow

Reputation: 27190

Is there any better way to write the same program?

Well, the thing is, the only good way to write the program is to use a single thread. If you want a program to do X, Y, and Z in that order, then write a procedure that does X, then Y, then Z. There is no better way than that.

Here's what I would have written after discussing the appropriateness of threads with the interviewer.

import java.util.concurrent.SynchronousQueue;
import java.util.function.Consumer;

public class EvenOdd {
    public static void main(String[] args) {
        SynchronousQueue<Object> q1 = new SynchronousQueue<>();
        SynchronousQueue<Object> q2 = new SynchronousQueue<>();
        Consumer<Integer> consumer = (Integer count) -> System.out.println(count);
        new Thread(new Counter(q1, q2, 2, 1, consumer)).start();
        new Thread(new Counter(q2, q1, 2, 2, consumer)).start();
        try {
            q1.put(new Object());
        } catch (InterruptedException ex) {
            throw new RuntimeException(ex);
        }
    }

    private static class Counter implements Runnable {
        final SynchronousQueue<Object> qin;
        final SynchronousQueue<Object> qout;
        final int increment;
        final Consumer<Integer> consumer;
        int count;

        Counter(SynchronousQueue<Object> qin, SynchronousQueue<Object> qout,
                int increment, int initial_count,
                Consumer<Integer> consumer) {
            this.qin = qin;
            this.qout = qout;
            this.increment = increment;
            this.count = initial_count;
            this.consumer = consumer;
        }

        public void run() {
            try {
                while (true) {
                    Object token = qin.take();
                    consumer.accept(count);
                    qout.put(token);
                    count += increment;
                }
            } catch (InterruptedException ex) {
                throw new RuntimeException(ex);
            }
        }
    }
}

Upvotes: 1

Tagir Valeev
Tagir Valeev

Reputation: 100299

Well, there are many alternatives. I would probably use a SynchronousQueue instead (I don't like low-level wait/notify and try to use higher-level concurrency primitives instead). Also printOdd and printEven could be merged into single method and no additional flags are necessary:

public class App {
    static class OddEven implements Runnable {
        private final SynchronousQueue<Integer> queue = new SynchronousQueue<>();

        public void start() throws InterruptedException {
            Thread oddThread = new Thread(this);
            Thread evenThread = new Thread(this);
            oddThread.start();
            queue.put(1);
            evenThread.start();
        }

        @Override
        public void run() {
            try {
                while (true) {
                    int i = queue.take();
                    System.out.println(i + " (" + Thread.currentThread() + ")");
                    if (i == 10)
                        break;
                    queue.put(++i);
                    if (i == 10)
                        break;
            } catch (InterruptedException e) {
                throw new RuntimeException(e);
            }
        }
    }

    public static void main(String[] args) throws InterruptedException {
        new OddEven().start();
    }
}

Upvotes: 1

xpa1492
xpa1492

Reputation: 1973

How about a shorter version like this:

public class OddEven implements Runnable {
    private static volatile int n = 1;

    public static void main(String [] args) {
        new Thread(new OddEven()).start();
        new Thread(new OddEven()).start();
    }

    @Override
    public void run() {
        synchronized (this.getClass()) {
            try {
                while (n < 10) {
                    this.getClass().notify();
                    this.getClass().wait();
                    System.out.println(Thread.currentThread().getName() + ": " + (n++));
                    this.getClass().notify();
                }
            } catch (InterruptedException ex) {
                ex.printStackTrace();
            }
        }
    }   
}

There is a bit of a trick to kick-start the threads properly - thus the need to an extra notify() to start the whole thing (instead of have both processes wait, or required the main Thread to call a notify) and also to handle the possibility that a thread starts, does it's work and calls notify before the second thread has started :)

Upvotes: 0

Related Questions