Google News
logo
Java Multithreading Interview Questions
Multithreading is a process of executing multiple threads simultaneously. Multithreading is used to obtain the multitasking. It consumes less memory and gives the fast and efficient performance. Its main advantages are:
 
* Threads share the same address space.
* The thread is lightweight.
* The cost of communication between the processes is low.
There are various benefits of multithreading as given below :

* Saves time and parallelism tasks. 
* Increase use of CPU resources and reduce costs of maintenance. 
* Allow the program to run continuously even if a part of it is blocked. 
* Improve performance as compared to traditional parallel programs that use multiple processes. 
* Allows to write effective programs that utilize maximum CPU time
* Improves the responsiveness of complex applications or programs. 
* If an exception occurs in a single thread, it will not affect other threads as threads are independent. 
* Less resource-intensive than executing multiple processes at the same time.
Threads are basically the lightweight and smallest unit of processing that can be managed independently by a scheduler. Threads are referred to as parts of a process that simply let a program execute efficiently with other parts or threads of the process at the same time. Using threads, one can perform complicated tasks in the easiest way. It is considered the simplest way to take advantage of multiple CPUs available in a machine. They share the common address space and are independent of each other.
A multitasking operating system is an operating system that gives you the perception of 2 or more tasks/jobs/processes running at the same time. It does this by dividing system resources amongst these tasks/jobs/processes and switching between the tasks/jobs/processes while they are executing over and over again. Usually, the CPU processes only one task at a time but the switching is so fast that it looks like the CPU is executing multiple processes at a time. They can support either preemptive multitasking, where the OS provides time to applications (virtually all modern OS), or cooperative multitasking, where the OS waits for the program to give back control (Windows 3.x, Mac OS 9, and earlier), leading to hangs and crashes. Also known as Timesharing, multitasking is a logical extension of multiprogramming.
 
Multitasking programming is of two types which are as follows :
 
1. Process-based Multitasking
2. Thread-based Multitasking
A process is a self contained execution environment and it can be seen as a program or application whereas Thread is a single task of execution within the process. Java runtime environment runs as a single process which contains different classes and programs as processes. Thread can be called lightweight process. Thread requires less resources to create and exists in the process, thread shares the process resources.
In Multi-Threaded programming, multiple threads are executing concurrently that improves the performance because CPU is not idle incase some thread is waiting to get some resources. Multiple threads share the heap memory, so it’s good to create multiple threads to execute some task rather than creating multiple processes. For example, Servlets are better in performance than CGI because Servlet support multi-threading but CGI doesn't.
Implementing Runnable interface is considered to be better approach than Extending Thread due to following reasons.

* Java does not support multiple inheritance so if you extend Thread class and you can not extend any other class which is needed in most of the cases.
* Runnable interface represents a task and this can be executed with help of Thread class or Executors.
* When you use inheritance, it is because you want to extend some properties of parent, modify or improve class behavior. But if you are extending thread class just to create thread, so it may not be recommended behavior for Object Oriented Programming.
Thread waits for lock associated with the object and notify other threads which are waiting for same lock.
 
If wait(), notify() and notifyAll() will be in thread class, then each thread has to be aware of status of another thread and that does not make sense as each thread runs independent of other thread and has no specific knowledge about other thread.
wait() is called, so that thread can wait on some condition. When condition is met, then thread has to give up the lock.
 
To give up the lock, thread has to own it first. Thread can acquire lock by enter into synchronized context.
 
If wait method is called outside of synchronized context, then it will throw IllegalMonitorStateException.
You can call sleep() and yield() method on current executing thread. If there is in wait state, you can not call these methods.
 
To avoid the confusion for programmers, there methods are made static.
The key benefits of Java multithreading include :
 
* Multiple threads can share single address spaces
* Threads share the same resources from the library but can execute differently
* Different threads can be made to perform various functions to yield a given result
* Multithreading allows an application/program to be always reactive for input, even already running with some background tasks
* Multithreading allows the faster execution of tasks, as threads execute independently.
* Multithreading provides better utilization of cache memory as threads share the common memory resources.
* Multithreading reduces the number of the required server as one server can execute multiple threads at a time.
Yes, we can call run() method of a Thread class but it will behave like a normal method and a new thread will not be created to execute the run() method. In this case the run() method will be executed in the same thread which called the run method. To actually execute it in a new Thread, we need to start it using Thread.start() method.
User and Daemon are basically two types of thread used in Java by using a ‘Thread Class’.  
 
User Thread (Non-Daemon Thread) : In Java, user threads have a specific life cycle and its life is independent of any other thread. JVM (Java Virtual Machine) waits for any of the user threads to complete its tasks before terminating it. When user threads are finished, JVM terminates the whole program along with associated daemon threads. 
 
Daemon Thread : In Java, daemon threads are basically referred to as a service provider that provides services and support to user threads. There are basically two methods available in thread class for daemon thread: setDaemon() and isDaemon().
New : When a thread is created either by extending Thread class or implementing Runnable interface it is in "New State".
Runnable : When we call start() method on the thread object that causes the thread to begin execution and it's the Java Virtual Machine that calls the run method of the thread.
Blocked : When a resource is shared among various threads then a thread may go into blocked state as the resource may be used by another thread.
Waiting : A thread that is waiting indefinitely for another thread to perform a particular action is in the waiting state.
Timed_Waiting : A thread that is waiting for another thread to perform an action for up to a specified waiting time is in timed_waiting state.
* The process of communication between synchronized threads is termed as inter-thread communication.
* Inter-thread communication is used to avoid thread polling in Java.
* The thread is paused running in its critical section, and another thread is allowed to enter (or lock) in the same critical section to be executed.
* It can be obtained by wait(), notify(), and notifyAll() methods.
A thread can have one of the following states during its lifetime :
 
New : In this state, a Thread class object is created using a new operator, but the thread is not alive. Thread doesn't start until we call the start() method.
Runnable : In this state, the thread is ready to run after calling the start() method. However, the thread is not yet selected by the thread scheduler.
Running : In this state, the thread scheduler picks the thread from the ready state, and the thread is running.
Waiting/Blocked : In this state, a thread is not running but still alive, or it is waiting for the other thread to finish.
Dead/Terminated : A thread is in terminated or dead state when the run() method exits.
Under preemptive scheduling, the highest priority task executes until it enters the waiting or dead states or a higher priority task comes into existence. Under time slicing, a task executes for a predefined slice of time and then reenters the pool of ready tasks. The scheduler then determines which task should execute next, based on priority and other factors.
Class Lock : In java, each and every class has a unique lock usually referred to as a class level lock. These locks are achieved using the keyword ‘static synchronized’ and can be used to make static data thread-safe. It is generally used when one wants to prevent multiple threads from entering a synchronized block. 
 
Example :  
public class ClassLevelLockExample  
{    
  public void classLevelLockMethod()  
 {       
     synchronized (ClassLevelLockExample.class)  
       {         
            //DO your stuff here       
       }    
 } 
} 
 
Object Lock : In java, each and every object has a unique lock usually referred to as an object-level lock. These locks are achieved using the keyword ‘synchronized’ and can be used to protect non-static data. It is generally used when one wants to synchronize a non-static method or block so that only the thread will be able to execute the code block on a given instance of the class.  
 
Example :  
public class ObjectLevelLockExample  
{    
  public void objectLevelLockMethod()  
 {   
     synchronized (this)  
       {     
            //DO your stuff here   
       } 
 }
}
The join() method waits for a thread to die. In other words, it causes the currently running threads to stop executing until the thread it joins with completes its task. Join method is overloaded in Thread class in the following ways.
 
* public void join()throws InterruptedException
* public void join(long milliseconds)throws InterruptedException

join() : When the join() method is invoked, the current thread stops its execution and the thread goes into the wait state. The current thread remains in the wait state until the thread on which the join() method is invoked has achieved its dead state. If interruption of the thread occurs, then it throws the InterruptedException.
 
Syntax :
public final void join() throws InterruptedException
The sleep() method in java is used to block a thread for a particular time, which means it pause the execution of a thread for a specific time. There are two methods of doing so.
 
Syntax :
public static void sleep(long milliseconds)throws InterruptedException
public static void sleep(long milliseconds, int nanos)throws InterruptedException
Working of sleep() method
When we call the sleep() method, it pauses the execution of the current thread for the given time and gives priority to another thread(if available). Moreover, when the waiting time completed then again previous thread changes its state from waiting to runnable and comes in running state, and the whole process works so on till the execution doesn't complete.
No, we cannot restart the thread, as once a thread started and executed, it goes to the Dead state. Therefore, if we try to start a thread twice, it will give a runtimeException "java.lang.IllegalThreadStateException". Consider the following example.
public class Multithread1 extends Thread  
{  
   public void run()  
    {  
      try {  
          System.out.println("thread is executing now........");  
      } catch(Exception e) {  
      }   
    }  
    public static void main (String[] args) {  
        Multithread1 m1= new Multithread1();  
        m1.start();  
        m1.start();  
    }  
}​
  
Output :
thread is executing now........
Exception in thread "main" java.lang.IllegalThreadStateException
	at java.lang.Thread.start(Thread.java:708)
	at Multithread1.main(Multithread1.java:13)
Garbage collection is basically a process of managing memory automatically. It uses several GC algorithms among which the popular one includes Mark and Sweep. The process includes three phases i.e., marking, deletion, and compaction/copying. In simple words, a garbage collector finds objects that are no longer required by the program and then delete or remove these unused objects to free up the memory space.
A volatile variable is basically a keyword that is used to ensure and address the visibility of changes to variables in multithreaded programming. This keyword cannot be used with classes and methods, instead can be used with variables. It is simply used to achieve thread-safety. If you mark any variable as volatile, then all the threads can read its value directly from the main memory rather than CPU cache, so that each thread can get an updated value of the variable.
Synchronization is basically a process in java that enables a simple strategy for avoiding thread interference and memory consistency errors. This process makes sure that resource will be only used one thread at a time when one thread tries to access a shared resource. It can be achieved in three different ways as given below: 
 
* By the synchronized method
* By synchronized block
* By static synchronization

Syntax :  
synchronized (object) 
{        
   //statement to be synchronized 
}
Thread Scheduler is the Operating System service that allocates the CPU time to the available runnable threads. Once we create and start a thread, it’s execution depends on the implementation of Thread Scheduler. Time Slicing is the process to divide the available CPU time to the available runnable threads. Allocation of CPU time to threads can be based on thread priority or the thread waiting for longer time will get more priority in getting CPU time. Thread scheduling can’t be controlled by java, so it’s always better to control it from application itself.
Context Switching is the process of storing and restoring of CPU state so that Thread execution can be resumed from the same point at a later point of time. Context Switching is the essential feature for multitasking operating system and support for multi-threaded environment.
java.util.Timer is a utility class that can be used to schedule a thread to be executed at a certain time in future. Java Timer class can be used to schedule a task to be run one-time or to be run at regular intervals.
 
java.util.TimerTask is an abstract class that implements Runnable interface and we need to extend this class to create our own TimerTask that can be scheduled using java Timer class.
The shutdown hook is a thread that is invoked implicitly before JVM shuts down. So we can use it to perform clean up the resource or save the state when JVM shuts down normally or abruptly. We can add shutdown hook by using the following method :
public void addShutdownHook(Thread hook){}    
Runtime r=Runtime.getRuntime();  
r.addShutdownHook(new MyThread());  
Some important points about shutdown hooks are :
 
* Shutdown hooks initialized but can only be started when JVM shutdown occurred.
* Shutdown hooks are more reliable than the finalizer() because there are very fewer chances that shutdown hooks not run.
* The shutdown hook can be stopped by calling the halt(int) method of Runtime class.
The Synchronized block can be used to perform synchronization on any specific resource of the method. Only one thread at a time can execute on a particular resource, and all other threads which attempt to enter the synchronized block are blocked.
 
* Synchronized block is used to lock an object for any shared resource.
* The scope of the synchronized block is limited to the block on which, it is applied. Its scope is smaller than a method.
We can detect the deadlock condition by running the code on cmd and collecting the Thread Dump, and if any deadlock is present in the code, then a message will appear on cmd.
 
Ways to avoid the deadlock condition in Java :
 
Avoid Nested lock : Nested lock is the common reason for deadlock as deadlock occurs when we provide locks to various threads so we should give one lock to only one thread at some particular time.
Avoid unnecessary locks : we must avoid the locks which are not required.
Using thread join : Thread join helps to wait for a thread until another thread doesn't finish its execution so we can avoid deadlock by maximum use of join method.
In Java, when we create the threads, they are supervised with the help of a Thread Scheduler, which is the part of JVM. Thread scheduler is only responsible for deciding which thread should be executed. Thread scheduler uses two mechanisms for scheduling the threads: Preemptive and Time Slicing.
 
Java thread scheduler also works for deciding the following for a thread :

* It selects the priority of the thread.
* It determines the waiting time for a thread
* It checks the Nature of thread
Thread starvation is basically a situation or condition where a thread won’t be able to have regular access to shared resources and therefore is unable to proceed or make progress. This is because other threads have high priority and occupy the resources for too long. This usually happens with low-priority threads that do not get CPU for its execution to carry on.
BlockingQueue basically represents a queue that is thread-safe. Producer thread inserts resource/element into the queue using put() method unless it gets full and consumer thread takes resources from the queue using take() method until it gets empty. But if a thread tries to dequeue from an empty queue, then a particular thread will be blocked until some other thread inserts an item into the queue, or if a thread tries to insert an item into a queue that is already full, then a particular thread will be blocked until some threads take away an item from the queue. 
CyclicBarrier and CountDownLatch, both are required for managing multithreaded programming. But there is some difference between them as given below : 
 
CyclicBarrier : It is a tool to synchronize threads processing using some algorithm. It enables a set of threads to wait for each other till they reach a common execution point or common barrier points, and then let them further continue execution. One can reuse the same CyclicBarrier even if the barrier is broken by setting it. 
 
CountDownLatch : It is a tool that enables main threads to wait until mandatory operations are performed and completed by other threads. In simple words, it makes sure that a thread waits until the execution in another thread completes before it starts its execution. One cannot reuse the same CountDownLatch once the count reaches 0.
Thready safety can be achieved if multiple threads can use a particular class function without the occurrence of the race condition. In Multithreaded programming, thread safety can be achieved by :

* Synchronization
* Use of atomic wrapper class
* Use of a volatile keyword
* Employing a lock-based mechanism
ConcurrentHashMap : It was introduced in Java 1.5 to store data using multiple buckets. As the name suggests, it allows concurrent read and writes operations to the map. It only locks a certain portion of the map while doing iteration to provide thread safety so that other readers can still have access to the map without waiting for iteration to complete.  
 
Hashtable : It is a thread-safe legacy class that was introduced in old versions of java to store key or value pairs using a hash table.  It does not provide any lock-free read, unlike ConcurrentHashMap. It just locks the entire map while doing iteration. 
 
ConcurrentHashMap and Hashtable, both are thread-safe but ConcurrentHashMap generally avoids read locks and improves performance, unlike Hashtable. ConcurrentHashMap also provides lock-free reads, unlike Hashtable. Therefore, ConcurrentHashMap is considered faster than Hashtable especially when the number of readers is more as compared to the number of writers.
ThreadLocal variables are special kinds of variables created and provided by the Java ThreadLocal class. These variables are only allowed to be read and written by the same thread. Two threads cannot be able to see each other’s ThreadLocal variable, so even if they will execute the same code, then there won't be any race condition and the code will be thread-safe.  
 
Example :  
public class ThreadLocalExp   
{   
     public static class MyRunnable implements Runnable    
   {   
       private ThreadLocal<Integer> threadLocal =   
              new ThreadLocal<Integer>();   
      @Override   
       public void run() {   
           threadLocal.set( (int) (Math.random() * 50D) );   
           try    
           {   
               Thread.sleep(1000);   
           } catch (InterruptedException e) {   
           }   
           System.out.println(threadLocal.get());   
       }   
   }   
   public static void main(String[] args)    
   {   
       MyRunnable runnableInstance = new MyRunnable();    
       Thread t1 = new Thread(runnableInstance);   
       Thread t2 = new Thread(runnableInstance);   
      // this will call run() method    
       t1.start();   
       t2.start();   
   }   
}​
 
Output : 
 
10 
33 
10 33
Lock interface was introduced in Java 1.5 and is generally used as a synchronization mechanism to provide important operations for blocking.  
 
Advantages of using Lock interface over Synchronization block : 
 
* Methods of Lock interface i.e., Lock() and Unlock() can be called in different methods. It is the main advantage of a lock interface over a synchronized block because the synchronized block is fully contained in a single method.  
* Lock interface is more flexible and makes sure that the longest waiting thread gets a fair chance for execution, unlike the synchronization block.
Atomic operations are performed in a single unit of task without interference from other operations. Atomic operations are necessity in multi-threaded environment to avoid data inconsistency.
 
int++ is not an atomic operation. So by the time one thread read its value and increment it by one, another thread has read the older value leading to the wrong result.
 
To solve this issue, we will have to make sure that increment operation on count is atomic, we can do that using Synchronization but Java 5 java.util.concurrent.atomic provides wrapper classes for int and long that can be used to achieve this atomically without the usage of Synchronization. Go to this article to learn more about atomic concurrent classes.
Concurrency API can be developed using the class and interfaces of java.util.Concurrent package. There are the following classes and interfaces in java.util.Concurrent package.
 
* Future
* Locks
* Phaser
* Executor
* FarkJoinPool
* CyclicBarrier
* Semaphore
* DelayQueue
* ThreadFactory
* BlockingQueue
* ExecutorService
* TimeUnit(Enum)
* CountDownLatch
* ScheduledExecutorService
Java Callable interface : In Java5 callable interface was provided by the package java.util.concurrent. It is similar to the Runnable interface but it can return a result, and it can throw an Exception. It also provides a run() method for execution of a thread. Java Callable can return any object as it uses Generic.
 
Syntax :
public interface Callable<V>
 
Java Future interface : Java Future interface gives the result of a concurrent process. The Callable interface returns the object of java.util.concurrent.Future.
 
Java Future provides following methods for implementation.
 
cancel(boolean mayInterruptIfRunning) : It is used to cancel the execution of the assigned task.
get() : It waits for the time if execution not completed and then retrieved the result.
isCancelled() : It returns the Boolean value as it returns true if the task was canceled before the completion.
isDone() : It returns true if the job is completed successfully else returns false.
FutureTask is the base implementation class of Future interface and we can use it with Executors for asynchronous processing. Most of the time we don’t need to use FutureTask class but it comes real handy if we want to override some of the methods of Future interface and want to keep most of the base implementation. We can just extend this class and override the methods according to our requirements. Check out Java FutureTask Example post to learn how to use it and what are different methods it has.
Some important concurrent API enhancements are :
 
ConcurrentHashMap compute(), forEach(), forEachEntry(), forEachKey(), forEachValue(), merge(), reduce() and search() methods.
CompletableFuture that may be explicitly completed (setting its value and status).

Executors newWorkStealingPool() method to create a work-stealing thread pool using all available processors as its target parallelism level.