Google

Jul 19, 2013

Core Java multi-thread coding -- printing odd and even numbers with two threads and a blocking queue

Core Java Coding Questions and Answers for beginner to intermediate level

Q1 Q2 Q3 Q4 Q5 Q6

This is an alternative approach using a blocking queue compared to using an AtomicInteger and a lock.

Q. Can you write code to print odd and even numbers by two threads in sequence?
A. Even though this is not a practical question, a handy beginner level question test your ability to write multi-threaded code.

Considerations:

Use a blocking queue: A BlockingQueue is used to have one thread produce objects, which another thread consumes.T he producing thread will keep producing new objects and insert them into the queue, until the queue reaches some upper bound on what it can contain. If the blocking queue reaches its upper limit, the producing thread is blocked while trying to insert the new object. The consuming thread keeps taking objects out of the blocking queue, and processes them. If the consuming thread tries to take an object out of an empty queue, the consuming thread is blocked until a producing thread puts an object into the queue.

You can use 2 blocking queues -- one for odd numbers and another for the even numbers.

Step: 1: Put 1 into the odd queue.

Step 2: The odd number thread 
  • takes the number out of the odd number queue
  • prints the odd number
  • increments the number by 1
  • puts the even number in the even number queue.
  • when the queue is empty, it is blocked.

Step 3: Similarly,  The even number thread

  • takes the number out of the even number queue
  • prints the even number
  • increments the number by 1
  • puts the odd number in the even number queue.
  • when the queue is empty, it is blocked. 

Here is the diagram that  depicts this.



Finally, here is the working code.

Step 1: The main class OddAndEvenSignalling. 



  
import java.util.concurrent.BlockingQueue;
import java.util.concurrent.ExecutorService;
import java.util.concurrent.Executors;
import java.util.concurrent.LinkedBlockingQueue;

public class OddAndEvenSignalling
{
    
    private static final int MAX_NUMBER = 10;
    
    public static void main(String[] args)
    {
        BlockingQueue<Integer> odds = new LinkedBlockingQueue<Integer>();
        BlockingQueue<Integer> evens = new LinkedBlockingQueue<Integer>();
        ExecutorService executorService = Executors.newFixedThreadPool(2);
        
        //odd numbers are removed from the "from" queue --> printed --> incremented --> placed on the "to" queue by one thread
        //"from" queue is "odd number" queue and "to" queue is "even number" queue
        executorService.submit(new TakeAndOfferNext(odds, evens, MAX_NUMBER));
        
        //even numbers are removed from the "from" queue --> printed --> incremented --> placed on the "to" queue by another thread
        //"from" queue is "even number" queue and "to" queue is "odd number" queue
        executorService.submit(new TakeAndOfferNext(evens, odds, MAX_NUMBER));
        odds.offer(1);
    }
}


Step 2: The callable class TakeAndOfferNext that executes the logic as depicted in the diagram.


  
import java.util.concurrent.BlockingQueue;
import java.util.concurrent.Callable;

public class TakeAndOfferNext implements Callable<Object>
{
    
    BlockingQueue<Integer> takeFrom;
    BlockingQueue<Integer> offerTo;
    int maxNumber;
    
    public TakeAndOfferNext(BlockingQueue<Integer> takeFrom, BlockingQueue<Integer> offerTo, int maxNumber)
    {
        this.takeFrom = takeFrom;
        this.offerTo = offerTo;
        this.maxNumber = maxNumber;
    }
    
    public Object call() throws Exception
    {
        print();
        return null;
    }
    
    public void print()
    {
        while (true)
        {
            try
            {
                int i = takeFrom.take(); //removes the value in the "from" queue
                System.out.println(Thread.currentThread().getName() + " --> " + i);
                offerTo.offer(i + 1);    //increments the value by 1 and puts it in the "to" queue.
                if (i >= (maxNumber - 1))
                {
                    System.exit(0);
                }
            }
            catch (InterruptedException e)
            {
                throw new IllegalStateException("Unexpected interrupt", e);
            }
        }
    }
    
}


Step 3: The output

  
pool-1-thread-2 --> 1
pool-1-thread-1 --> 2
pool-1-thread-2 --> 3
pool-1-thread-1 --> 4
pool-1-thread-2 --> 5
pool-1-thread-1 --> 6
pool-1-thread-2 --> 7
pool-1-thread-1 --> 8
pool-1-thread-2 --> 9
pool-1-thread-1 --> 10


Labels: ,

5 Comments:

Anonymous Anonymous said...

excellent example. got good understanding about usage of blocking queue

9:28 PM, December 06, 2013  
Blogger Pankaj Kr said...

Hi Arul, I want to print sequence of integers with two threads say upto 10. First I want Thread A to print 1 then thread B to print 1 something like below

pool-1-thread-2 --> 1
pool-1-thread-1 --> 1
pool-1-thread-2 --> 2
pool-1-thread-1 --> 2
pool-1-thread-2 --> 3
pool-1-thread-1 --> 3
pool-1-thread-2 --> 4
pool-1-thread-1 --> 4
pool-1-thread-2 --> 5
pool-1-thread-1 --> 5
...... with a pause of 1 sec

1:28 AM, March 24, 2014  
Anonymous Anonymous said...

Hi Arul,
I suggest to use explicit lock with a condition queue where threads will co-operate by signal.

12:03 AM, June 11, 2014  
Blogger Arulkumaran Kumaraswamipillai said...

Any benefits over intrinsic locks?

4:14 PM, June 11, 2014  
Anonymous Anonymous said...

it can also be implemented using SynchronousQueue.

7:03 PM, June 18, 2014  

Post a Comment

Subscribe to Post Comments [Atom]

<< Home