The Java multi-threading questions are very popular with the job interviewers as it can be not only hard to grasp, but also concurrency issues are very hard to debug and fix. So, it really pays to have people with the good understanding in this key area. We looked at some basic questions and answers at Java multi-threading questions and answers. Let's look at more coding based questions and answers to build up on what we had learned before. |
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.IllegalThreadStateException
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) {
NumberUtility numUtility = new NumberUtility(); //single instance shared by oddGen and evenGen threads
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);
oddGen.start(); //start the thread - invokes the run() method on NumberGenerator
evenGen.start(); //start the thread - invokes the run() method on NumberGenerator
}
}
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
Note: The above problem can also be solved with a blocking queue as described in multi-threading with blocking queues questions and answers.
Java multi-threading interview questions and answers: overview
Java multi-threading questions and answers with blocking queue