Multi Threading Java Interview Questions – Set 07

How will you fix the above racing issue

This can be fixed a number of ways.

Option 1: Method level synchronization. This is the simplest. As you can see, the increment() method is synchronized, so that the other threads must wait for the thread that already has the lock to execute that method.

import java.util.HashMap;

import java.util.Map;

public class Counter {

//shared variable or resource

private Integer count = Integer.valueOf(0);

private Map<String, Integer> userToNumber = new HashMap<String, Integer>(10);

public synchronized void  increment() {

try {

count = count + 1;

Thread.sleep(50);

Thread thread = Thread.currentThread();

userToNumber.put(thread.getName(), count);

} catch (InterruptedException e) {

e.printStackTrace();

}

}

public Integer getCount(String name) {

return userToNumber.get(name);

}

}

Option 2: Even though the Option 1 is simple, it locks the entire method and can adversely impact performance for long running methods as each thread has to execute the entire method one at a time. So, the Option 1 can be improved by providing block level lock. Lock only those operations that are acting on the shared resource and making it non-atomic.

The code below uses an Object, which has its own lock to ensure that two threads cannot execute both the Operation 1 and 2 at the same time because there is only one lock.

import java.util.HashMap;

import java.util.Map;

public class Counter {

//shared variable or resource

private Integer count = Integer.valueOf(0);

private Map<String, Integer> userToNumber = new HashMap<String, Integer>(10);

private Object mutex = new Object();   // a lock

public void  increment() {

try {

synchronized(mutex) {

count = count + 1;                         //operation 1

Thread.sleep(50);

Thread thread = Thread.currentThread();

userToNumber.put(thread.getName(), count); //operation 2

}

// there could be other operations here that uses the shared resource as read only

} catch (InterruptedException e) {

e.printStackTrace();

}

}

public Integer getCount(String name) {

return userToNumber.get(name);

}

}

Option 3: This is a very trivial, but practical example. The Java 5 introduced locks and locks are better than using just objects for more flexible locking scenarios where Locks can be used in place of synchronized blocks. Locks offer more flexibility than synchronized blocks in that a thread can unlock multiple locks it holds in a different order than the locks were obtained. Here is the code that replaces synchronized with a reentrant lock. Synchronized blocks in Java are reentrant, which means if a Java thread enters a synchronized block of code, and thereby take the lock on the object the block is synchronized on, the thread can enter other Java code blocks synchronized on the same lock object.

For example, here is the demo of reentrant lock.

public class Reentrant{

public synchronized method1(){

method2();    //calls another synchronized method on the same object

}

public synchronized method2(){

//do something

}

}

Here is the Option 3 example using a ReentrantLock.

import java.util.HashMap;

import java.util.Map;

import java.util.concurrent.locks.Lock;

import java.util.concurrent.locks.ReentrantLock;

public class Counter {

// shared variable or resource

private Integer count = Integer.valueOf(0);

private Map<String, Integer> userToNumber = new HashMap<String, Integer>(10);

private Lock mutex = new ReentrantLock(); // a lock

public void increment() {

try {

mutex.lock();

try {

count = count + 1;

Thread.sleep(50);

Thread thread = Thread.currentThread();

userToNumber.put(thread.getName(), count);

} finally {

mutex.unlock(); // finally block is executed even if an

// exception is thrown

}

} catch (InterruptedException e) {

e.printStackTrace();

} finally {

}

}

public Integer getCount(String name) {

return userToNumber.get(name);

}

}

Note that the locks are unlocked in a finally block as it is executed even if an exception is thrown.

The output for the above 3 options will be something like shown below. The order cannot be guaranteed.

But you will get unique numbers assigned for each user.

User-1 value is 1

User-3 value is 2

User-2 value is 3

What is ThreadLocal class? How can it be used

Below are some key points about ThreadLocal variables

  • A thread-local variable effectively provides a separate copy of its value for each thread that uses it.
  • ThreadLocal instances are typically private static fields in classes that wish to associate state with a thread
  • In case when multiple threads access a ThreadLocal instance, separate copy of Threadlocal variable is maintained for each thread.
  • Common use is seen in DAO pattern where the DAO class can be singleton but the Database connection can be maintained separately for each thread. (Per Thread Singleton)
  • ThreadLocal variable are difficult to understand and I have found below reference links very useful in getting better understanding on them
  • “http://www-128.ibm.com/developerworks/java/library/j-threads3.html”Good article on ThreadLocal on IBM DeveloperWorks
  • “http://javaboutique.internet.com/tutorials/localdata”Managing data : Good example
  • href=”http://java.sun.com/j2se/1.4.2/docs/api/java/lang/ThreadLocal.html”Refer Java API Docs

Which one would you prefer and why

The Runnable interface is preferred, as it does not require your object to inherit a thread because when you need multiple inheritance, only interfaces can help you. In the above example we had to extend the Base class so implementing Runnable interface is an obvious choice.

Also note how the threads are started in each of the different cases as shown inthe code sample. In an OO approach you should only extend a class when you want to make it different from it’s superclass, and change it’s behavior.

By implementing a Runnable interface instead of extending the Thread class, you are telling to the user that the class Counter is an object of type Base and will run as a thread.

What happens if you restart a thread that has already started

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)

How can I trace whether the application has a thread leak

If an application has thread leak then with time it will have too many unused threads. Try to find out what type of threads is leaking out.

This can be done using following ways:

  • Give unique and descriptive names to the threads created in application. – Add log entry in all thread at various entry and exit points in threads.
  • Change debugging config levels (debug, info, error etc) and analyze log messages.
  • When you find the class that is leaking out threads check how new threads are instantiated and how they’re closed.
  • Make sure the thread is Guaranteed to close properly by doing following – Handling all Exceptions properly.
  • Make sure the thread is Guaranteed to close properly by doing following
  • Handling all Exceptions properly.
  • releasing all resources (e.g. connections, files etc) before it closes.

Briefly explain high-level thread states

The state chart diagram below describes the thread states.

Runnable: A thread becomes runnable when you call the start( ), but does  not necessarily start running immediately.  It will be pooled waiting for its turn to be picked for execution by the thread scheduler based on thread priorities.

MyThread aThread = new MyThread();

aThread.start();                   //becomes runnable

Running: The processor is actively executing the thread code. It runs until it becomes blocked, or voluntarily gives up its turn with this static method Thread.yield( ). Because of context switching overhead, yield( ) should not be used very frequently

Waiting: A thread is in a blocked state while it waits for some external processing such as file I/O to finish.A call to currObject.wait( ) method causes the current thread to wait until some other thread invokescurrObject.notify( ) or the currObject.notifyAll( ) is executed.

Sleeping: Java threads are forcibly put to sleep (suspended) with this overloaded method: Thread.sleep(milliseconds), Thread.sleep(milliseconds, nanoseconds);

Blocked on I/O: Will move to runnable after I/O condition like reading bytes of data etc changes.

Blocked on synchronization: will move to running when a lock is acquired.

Dead: The thread is finished working.

Thread.State enumeration contains the possible states of a Java thread in the underlying JVM. These thread states are possible due to Java’s following thread concepts:

  • The objects can be shared and modified (i.e. if mutable) by any threads.
  • The preemptive nature of the thread scheduler can swap threads on and off cores in a multi-core CPU machine at any time.
  • This means the methods can be swapped out while they are running. Otherwise a method in an infinite loop will clog the CPU forever leaving the other methods on different threads to starve.
  • To prevent thread safety issues, the methods and block of code that has vulnerable data can be locked.
  • This enables the threads to be in locked or waiting to acquire a lock states.
  • The threads also get into the waiting state for I/O resources like sockets, file handles, and database connections.
  • The threads that are performing I/O read/write operations can not be swapped. Hence, they need to eithercomplete to the finished state with success/failure or another thread must close the socket for it to get to the state of dead or finished. This is why proper service timeout values are necessary to prevent the thread to get blocked for ever in an I/O operation, causing performance issues.
  • The threads can be put to sleep to give other threads in waiting state an opportunity to execute.

What is thread pool? Why should we use thread pools

A thread pool is a collection of threads on which task can be scheduled. Instead of creating a new thread for each task, you can have one of the threads from the thread pool pulled out of the pool and assigned to the task. When the thread is finished with the task, it adds itself back to the pool and waits for another assignment. One common type of thread pool is the fixed thread pool. This type of pool always has a specified number of threads running; if a thread is somehow terminated while it is still in use, it is automatically replaced with a new thread. Below are key reasons to use a Thread Pool

  • Using thread pools minimizes the JVM overhead due to thread creation. Thread objects use a significant amount of memory, and in a large-scale application, allocating and de-allocating many thread objects creates a significant memory management overhead.
  • You have control over the maximum number of tasks that are being processed in parallel (= number of threads in the pool).

Most of the executor implementations in java.util.concurrent use thread pools, which consist of worker threads. This kind of thread exists separately from the Runnable and Callable tasks it executes and is often used to execute multiple tasks.

The following code snippet changes the Counter class to maintain individual counting as in each user counter will be incremented starting from 1.

The following code snippet changes the Counter class to maintain individual counting as in each user counter will be incremented starting from 1. So, the Counter will no longer be the shared resource. The CountingTask class is also modified to loop through each user 2 times as shown below. Is there anything wrong with the code shown below

The Counter class with individual counts

import java.util.HashMap;

import java.util.Map;

 

public class Counter {

 

 private Map<String, Integer> userToNumber = new HashMap<String, Integer>(10);

 

 public void increment() {

  Thread thread = Thread.currentThread();

  if (!userToNumber.containsKey(thread.getName())) {

   userToNumber.put(thread.getName(), Integer.valueOf(1));  //op1

  } else {

   Integer count = userToNumber.get(thread.getName());

   if (count != null) {

    ++count; // op2: increment it

    userToNumber.put(thread.getName(), count); //op3

   }

  }

}

 

 public Integer getCount(String name) {

  return userToNumber.get(name);

 }

}

 

// The counting task that repeats twice for each user

public class CountingTask implements Runnable {

 

 private Counter counter;

 

 public CountingTask(Counter counter) {

  super();

  this.counter = counter;

 }

 

public void run() {

 

  for (int i = 0; i < 2; i++) {

   counter.increment();

   Thread thread = Thread.currentThread();

   System.out.println(thread.getName() + ” value is “

     + counter.getCount(thread.getName()));

  }

 }

}

If each user will be accessed by only one thread, then the above code is thread-safe because each user will be operating on his/her data.

So, only one thread will access the map entry for User-1, and so on.

But, what happens if User-3 has two threads created as shown below.

The Thread 3 and 4 are User 3.

In this scenario, the above code is not thread safe, and it needs to be made atomic with one of the three options discussed above. It can be quite dangerous to assume that one user will be accessed only by one thread.What if in the future, additional threads are added to improve performance per user?

public class CountingManager

{

public static void main(String[] args) throws InterruptedException

{

Counter counter = new Counter(); // create an instance of the Counter

CountingTask task = new CountingTask(counter); // pass the counter to the runnable CountingTask

//Create 10 user threads (non-daemon) from the main thread that share the counter object

Thread thread1 = new Thread(task, “User-1”);

Thread thread2 = new Thread(task, “User-2”);

Thread thread3 = new Thread(task, “User-3”); //user 3

Thread thread4 = new Thread(task, “User-3”); //User 3

//start the threads

thread1.start();

thread2.start();

thread3.start();

thread4.start();

//observe the racing conditions in the output

}

}

If you don’t perform the operations 1 to 3 atomically (i.e. as a unit),

you will get an out put like:

User-1 value is 1

User-1 value is 2

User-3 value is 2

User-3 value is 3

User-3 value is 2

User-3 value is 4

User-2 value is 1

User-2 value is 2

As you can see, the User-3 has the value 2 repeated twice and value 1 is missing. If you apply the one of the options outlined above, you will get an output like:

User-1 value is 1

User-1 value is 2

User-3 value is 1

User-3 value is 2

User-2 value is 1

User-2 value is 2

User-3 value is 3

User-3 value is 4

Hence, the operations 1-3 need to be made atomic if accessed concurrently by multiple threads.Those three operations are

  • storing the initial value
  • incrementing the counter
  • storing the incremented value

Can you write a program with 2 threads, in which one prints odd numbers and the other prints even numbers up to

In Java, you can use wait(  ) and notifyAll(  ) to communicate between threads. The code below demonstrates that:

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.

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(); //<span id=”IL_AD6″ class=”IL_AD”>single</span> 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

In Java, you can use wait(  ) and notifyAll(  ) to communicate between threads. The code below demonstrates that:

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.

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(); //<span id=”IL_AD6″ class=”IL_AD”>single</span> 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

What is Starvation? And what is a Livelock

Starvation and livelock are much less common a problem than deadlock, but are still problems that every designer of concurrent software is likely to encounter.

LiveLock

Livelock occurs when all threads are blocked, or are otherwise unable to proceed due to unavailability of required resources, and the non-existence of any unblocked thread to make those resources available. In terms of Java API, thread livelock can occur in following conditions:

  • When all the threads in a program execute Object.wait(0) on an object with zero parameter. The program is live-locked and cannot proceed until one or more threads call Object.notify() or Object.notifyAll() on the relevant objects. Because all the threads are blocked, neither call can be made.
  • When all the threads in a program are stuck in infinite loops.

Starvation

Starvation describes a situation where a thread is unable to gain regular access to shared resources and is unable to make progress. This happens when shared resources are made unavailable for long periods by “greedy” threads. For example, suppose an object provides a synchronized method that often takes a long time to return. If one thread invokes this method frequently, other threads that also need frequent synchronized access to the same object will often be blocked. Starvation occurs when one thread cannot access the CPU because one or more other threads are monopolizing the CPU. In Java, thread starvation can be caused by setting thread priorities inappropriately. A lower-priority thread can be starved by higher-priority threads if the higher-priority threads do not yield control of the CPU from time to time.