Monday, June 11, 2012

Java multi-threading interview questions and answers - coding

Q. Explain how you would get a Thread Deadlock with a code example?
A. The example below causes a deadlock situation by thread-1 waiting for lock2 and thread-0 waiting for lock1.





package deadlock;
public class DeadlockTest extends Thread {
    public static Object lock1 = new Object();
    public static Object lock2 = new Object();
    public void method1() {
        synchronized (lock1) {
            delay(500);  //some operation
            System.out.println("method1: " + Thread.currentThread().getName());
            synchronized (lock2) {
                System.out.println("method1 is executing .... ");
            }
        }
    }
    public void method2() {
        synchronized (lock2) {
            delay(500);   //some operation
            System.out.println("method1: " + Thread.currentThread().getName());
            synchronized (lock1) {
                System.out.println("method2 is executing .... ");
            }
        }
    }
    @Override
    public void run() {
        method1();
        method2();
    }
    public static void main(String[] args) {
        DeadlockTest thread1 = new DeadlockTest();
        DeadlockTest thread2 = new DeadlockTest();
        thread1.start();
        thread2.start();
    }
    /**
     * The delay is to simulate some real operation happening.
     * @param timeInMillis
     */
    private void delay(long timeInMillis) {
        try {
            Thread.sleep(timeInMillis);
        } catch (InterruptedException e) {
            e.printStackTrace();
        }
    }
}

The output will be something like:


method1: Thread-0
method1 is executing ....
method2: Thread-0
method1: Thread-1
---deadlock ----- can't proceed further

Q. What happens if you restart a thread that has already started?
A. You will get the following exception

Exception in thread "main" java.lang.<b>IllegalThreadStateException</b>
 at java.lang.Thread.start(Thread.java:595)
 at deadlock.DeadlockTest.main(DeadlockTest.java:38)



Q. Can you write a program with 2  threads, in which one prints odd numbers and the other prints even numbers up to 10?
A. In Java, you can use wait(  ) and notifyAll(  ) to communicate between threads. The code below demonstrates that.



Firstly, create the thread classes and the main method that creates the thread and run it.

package multithreading;
public class NumberGenerator extends Thread {
    private NumberUtility numberUtility;
    private int maxNumber;
    private boolean isEvenNumber;
     
    public NumberGenerator(NumberUtility numberUtility, int maxNumber, boolean isEvenNumber) {
        this.numberUtility = numberUtility;
        this.maxNumber = maxNumber;
        this.isEvenNumber = isEvenNumber;
    }
    public void run() {
        int i = isEvenNumber == true ? 2 : 1;
        while (i <= maxNumber) {
            if(isEvenNumber == true) {
                numberUtility.printEven(i);
            }
            else {
                numberUtility.printOdd(i);   
            }
             
            i = i + 2;
        }
    }
     public static void main(String[] args) {
     //single instance shared by oddGen and evenGen threads
     NumberUtility numUtility = new NumberUtility();
     final int MAX_NUM = 10; 
     //create 2 threads, one to generate odd numbers and 
     //the other to generate even numbers
     NumberGenerator oddGen = new NumberGenerator(numUtility, MAX_NUM, false);
     NumberGenerator evenGen = new NumberGenerator(numUtility, MAX_NUM, true);
     //start the thread - invokes the run() method on NumberGenerator
     oddGen.start();
     //start the thread - invokes the run() method on NumberGenerator  
     evenGen.start(); 
   }
}

Next, create the utility class that is used for communicating between the two threads with wait() and notifyAll() methods via synchronized methods.


package multithreading;
import static java.lang.System.out;
public class NumberUtility {
    boolean oddPrinted = false;
    public synchronized void printOdd(int number) {
        while (oddPrinted == true) {
            try {
                wait();   // waits until notified by even thread
            } catch (InterruptedException e) {
                e.printStackTrace();
            }
        }
        out.println("printOdd() " + number);
        oddPrinted = true;
        notifyAll();  //notify all waiting threads
    }
    public synchronized void printEven(int number) {
        while (oddPrinted == false) {
            try {
                wait();  //waits until notified by the odd thread
            } catch (InterruptedException e) {
            }
        }
        oddPrinted = false;
        out.println("printEven() " + number);
        notifyAll();  //notify all waiting threads
    }
}

The output will be something like

printOdd() 1
printEven() 2
printOdd() 3
printEven() 4
printOdd() 5
printEven() 6
printOdd() 7
printEven() 8
printOdd() 9
printEven() 10 


Note: This a typical example of splitting tasks among threads. A method calls notify/notifyAll( ) as the last thing it does (besides return). Since the printOdd( ) and printEven( ) methods were void, the notifyAll( ) was the last statement. If it were to return some value, the notifyAll( ) would have been placed just before the return statement.

Q. Write a multi-threaded Java program in which, one thread generates odd numbers and write to a pipe and the second thread generates even numbers and write to another pipe, and a third thread receives the numbers from both the pipes and evaluates if the sum is multiples of 5?

A. In Unix, a pipe (“|”) operator helps you to redirect output from one command to another. PipedReader and PipedWriter classes in java.io package helps you to do the same. It helps you to redirect the read input into writer seamlessly. In Unix, two different processes on different address spaces can communicate using pipe, but in java two threads on the JVM can communicate using Piped ByteStream/CharacterStream within the same process (i.e same address space)



Here is the code snippet. The Writer threads responsible for writing odd and even numbers to the respective pipes.

package multithreading;
import java.io.IOException;
import java.io.PipedWriter;
public class NumberWriter extends Thread {
    private PipedWriter writer;
    private int maxNumber;
    private boolean isEvenNumber;
    public NumberWriter(PipedWriter writer, int maxNumber, boolean isEvenNumber) {
        this.writer = writer;
        this.maxNumber = maxNumber;
        this.isEvenNumber = isEvenNumber;
    }
    public void run() {
        int i = 1;
        while (i <= maxNumber) {
            try {
                if (isEvenNumber && (i % 2) == 0) {
                    writer.write(i);
                } else if (!isEvenNumber && i%2 != 0) {
                    writer.write(i);
                }
                ++i;
            } catch (IOException e) {
                e.printStackTrace();
            }
        }
    }
    public static void main(String[] args) {
        final int MAX_NUM = 10;
        PipedWriter oddNumberWriter = new PipedWriter();
        PipedWriter evenNumberWriter = new PipedWriter();
        NumberWriter oddGen = new NumberWriter(oddNumberWriter, MAX_NUM, false);
        NumberWriter evenGen = new NumberWriter(evenNumberWriter, MAX_NUM, true);
        NumberReceiver receiver = new NumberReceiver(oddNumberWriter, evenNumberWriter);
        oddGen.start();
        evenGen.start();
        receiver.start();
    }
}

The receiver thread that listens to both odd and even number pipes and computes the sum. If the sum is a multiple of 5, it prints the numbers and the sum.



package multithreading;
import java.io.IOException;
import java.io.PipedReader;
import java.io.PipedWriter;
public class NumberReceiver extends Thread {
    private PipedReader oddReader;
    private PipedReader evenReader;
    public NumberReceiver(PipedWriter oddWriter, PipedWriter evenWriter) {
        try {
            this.oddReader = new PipedReader(oddWriter);
            this.evenReader = new PipedReader(evenWriter);
        } catch (IOException e) {
            e.printStackTrace();
        }
    }
    public void run() {
        int odd =0, even=0;
         
        try {
            while (odd != -1) {
                odd = oddReader.read();
                even = evenReader.read();
                 
                if ((odd + even) % 5 == 0) {
                    System.out.println("match found " + odd + " + " + even + " = " + (odd + even));
                }
            }
                
        } catch (IOException e) {
            System.exit(1);
        }
        
         
    }
}

The output will be something like

match found 7 + 8 = 15

No comments:

Post a Comment