Thread and Exception Handling
Thread and Exception Handling
An Exception refers to abnormal behaviour of an application that occurs at the time of execution
that could lead to the termination of that application if not handled. Exceptions could include
sudden network errors, database connection errors, errors due to non-existent or corrupt files,
logical errors that were not handled by the developers and many more. Java provides a great way
of handling Exceptions that results in a robust application that does not fail in case of
abnormalities. Due to its importance, exception handling has become a very important and
favourite topic amongst interviewers. Every software developer should know how to handle
unexpected errors while developing an application.
An exception is an abnormal event that disrupts the flow of normal program execution that unless
handled could lead to the termination of that program. In real-world scenarios, a program could
run into an exception if it tries to access a corrupted/non-existent file or if a network error
happens or if the JVM runs out of memory, or if the code is trying to access an index of an array
which does not exist
2. What is exception handling in Java and what are the advantages of exception handling?
Exception Handling is the technique of handling unexpected failures that could occur in a program
so that the program does not terminate and normal execution flow is maintained. Consider an
example program where we have 6 statement blocks as shown in the below image. Statements 1
and 2 execute successfully. While executing the statement 3 block, an unexpected error occurred.
Now the Java program checks if there is any exception-handling mechanism present. If an
exception handling block is present, then the exception is handled gracefully and the program
continues with the execution of the statement 4 block. If not, the program gets terminated.
The following are some of the Advantages of using Exception Handling in Java:
try-catch block: The try section holds the code that needs to be normally executed and it monitors
for any possible exception that could occur. The catch block “catches” the exception thrown by the
try block. It could consist of logic to handle failure scenario or the catch block could simply rethrow
the exception by using the “throw” keyword.
finally block: Regardless of whether an exception has occurred or not, if we need to execute any
logic, then we place it in the final block that is usually associated with the try-catch block or just
with the try block. The final block is not executed when System.exit(0) is present in either the try
or catch block.
Consider an example where we need to get the value of the score from a file called “resultFile”.
When we access the file, the file could exist and we get the score and everything happens
normally. But there could be cases where the file was accidentally deleted. In this case, when the
program tries to access that file, then it throws FileNotFoundException. There are 2 ways to handle
this exception (Depending on the requirements, we need to choose what way is the most
appropriate for us):-
Case 1: Throw IllegalArgumentException stating the file does not exist as shown in the logic
below.
try {
return Integer.parseInt(contents.nextLine());
Case 2: Return the score as 0 and log the error that file doesn’t exist as shown in the logic below.
try {
return Integer.parseInt(contents.nextLine());
return 0;
Finally, irrespective of whether the code running normally or not, we would want to close the
resources. This could run in the finally block as shown below:
Scanner fileContents;
try {
return Integer.parseInt(contents.nextLine());
return 0;
} finally {
if (fileContents != null) {
fileContents.close();
Note:
As of Java 7, the new feature “try-with-resources” helps to autoclose the resources that extend the
“AutoCloseable” interface. The close() method will be called when it exits the try-with-resources
block. For example, the above code which has a close() method call could be simplified as shown
below:
return Integer.parseInt(contents.nextLine());
} catch (FileNotFoundException e ) {
Sometimes, the program could throw more than 1 exception. In this case, Java supports the usage
of multiple catch blocks. Our example could also encounter a NumberFormatException exception
while parsing integer numbers and this could be handled as shown below:
return Integer.parseInt(contents.nextLine());
} catch (FileNotFoundException e ) {
return 0;
} catch (NumberFormatException e) {
return 0;
Multiple catch blocks are useful if we have different exception-handling logic for different types of
exceptions. If our logic of handling the exception is the same (as in the above scenario), then Java7
introduced the feature to union the catch blocks - handle multiple exceptions in the same catch
block. The above could now be simplified to:
return Integer.parseInt(contents.nextLine());
return 0;
}
4. What is exception propagation in Java?
Exception propagation is a process where the compiler makes sure that the exception is handled if
it is not handled where it occurs. If an exception is not caught where it occurred, then the
exception goes down the call stack of the preceding method and if it is still not caught there, the
exception propagates further down to the previous method. If the exception is not handled
anywhere in between, the process continues until the exception reaches the bottom of the call
stack. If the exception is still not handled in the last method, i.e, the main method, then the
program gets terminated. Consider an example -
We have a Java program that has a main() method that calls method1() and this method, in turn,
calls another method2(). If an exception occurs in method2() and is not handled, then it is
propagated to method1(). If method1() has an exception handling mechanism, then the
propagation of exception stops and the exception gets handled. The same has been represented in
the image below:
The throwable class is the base class of Exception. Exception and its subclasses do not provide
specific methods. All the methods that could be used by Exception are defined in the Throwable
class. Some of the most important methods are as follows:
String getMessage(): This method returns the Throwable message of type String. The message
could be given at the time of creating an exception by using the constructor.
String getLocalizedMessage(): This method can be overridden by the Exception and its subclasses
to give locale-specific messages to the calling program. The implementation of this method in the
Throwable class by default uses the getMessage() that returns the exception message. Hence, to
use this method, it should be overridden to avoid this default behaviour.
synchronized Throwable getCause(): This returns the exception cause if it is known. If the cause is
not known, it returns null. The cause is returned if it was provided via the constructors
requiring Throwable or if it was set after the creation of exception by using
the initCause(Throwable) method. Exception and its subclasses may override this method to return
a cause set by different means.
String toString(): This returns the Throwable information in String format consisting of the
Throwable class name and localized message.
void printStackTrace(): As the name indicates, this prints the stack trace data to the standard error
stream. By default, it prints on the console. But, there are overloaded versions of this method
where we can pass either PrintWriter or PrintStream as an argument to write stack trace data to a
specific file or stream.
Runtime exceptions are those exceptions that occur at the run time of the program execution.
These exceptions are not noticed by the compiler at the compile time and hence the program
successfully gets compiled. Therefore, they are also called unchecked exceptions. All subclasses of
the java.lang.RunTimeException class and java.lang.Error class belongs to runtime exceptions.
Examples of runtime exceptions include NullPointerException, NumberFormatException,
ArrayIndexOutOfBoundException, StackOverflowError, ClassCastException, ArithmeticException,
ConcurrentModificationException, etc.
7. What is the difference between the throw and throws keywords in Java?
The throw keyword allows a programmer to throw an exception object to interrupt normal
program flow. The exception object is handed over to the runtime to handle it. For example, if we
want to signify the status of a task is outdated, we can create an OutdatedTaskException that
extends the Exception class and we can throw this exception object as shown below:
if (task.getStatus().equals("outdated")) {
The throws keyword in Java is used along with the method signature to specify exceptions that the
method could throw during execution. For example, a method could
throw NullPointerException or FileNotFoundException and we can specify that in the method
signature as shown below:
// do something
Checked Exceptions can be handled by either using a try-catch block or by using the throws clause
in the method declaration. If these exceptions are not handled properly, then the program would
fail to compile.
9. Differentiate between Checked Exception and Unchecked Exceptions in Java.
The followings programs are the differences between Checked and Unchecked Exceptions:
These exceptions are a direct subclass of These exceptions are a direct subclass of
the Exception class. the RuntimeException class.
Examples: ArithmeticException,
Examples: IOException, FileNotFoundException,
ArrayIndexOutOfBoundException,
DataAccessException, InterruptedException, etc.
NullPointerException, InvalidClassException, etc.
Since Exception is the base class for all exception types, make use of a catch block that catches the
Exception class-
try {
// do something
// handle exception
However, it is recommended to use accurate Exception handlers instead of generic ones. This is
because having broad exception handlers could make the code error-prone by catching exceptions
that were not anticipated in the software design and could result in unexpected behavior.
From Java 7 onwards, it is now possible to implement multiple catch blocks as shown below -
try {
// do something
// handle EOFException
When we are using multiple catch blocks, we need to ensure that in a case where the exceptions
have an inheritance relationship, the child exception type should be the first and the parent type
later to avoid a compilation error.
Java 7 also began to provide the usage of multi-catch blocks for reducing duplication of code if the
exception handling logic was similar for different exception types. The syntax of the multi-catch
block is as shown below-
try {
// ...
// ...
A stack trace is information consisting of names of classes and methods that were invoked right
from the start of program execution to the point where an exception occurred. This is useful to
debug where exactly the exception occurred and due to what reasons. Consider an example stack
trace in Java,
at com.example.demoProject.Book.getBookTitle(Book.java:26)
at com.example.demoProject.Author.getBookTitlesOfAuthor(Author.java:15)
at com.example.demoProject.DemoClass.main(DemoClass.java:14)
To determine where an exception has occurred, we need to check for the beginning of the trace
that has a list of “at …”. In the given example, the exception has occurred at Line Number 26 of
the Book.java class in the getBookTitle() method. We can look at this stack trace and go to the
method and the line number mentioned in the trace and debug for what could have caused the
NullPointerException. Furthermore, we can get to know that the getBookTitle() method in
the Book.java class was called by the getBookTitlesOfAuthor() method in the Author.java class in
Line Number 15 of the file and this in turn was called by the main() method of
the DemoClass.java file in Line Number 14.
Exception Chaining happens when one exception is thrown due to another exception. This helps
developers to identify under what situation an Exception was thrown that in turn caused another
Exception in the program. For example, we have a method that reads two numbers and then
divides them. The method throws ArithmeticException when we divide a number by zero. While
retrieving the denominator number from the array, there might have been an IOException that
prompted to return of the number as 0 that resulted in ArithmeticException. The original root
cause in this scenario was the IOException. The method caller would not know this case and they
assume the exception was due to dividing a number by 0. Chained Exceptions are very useful in
such cases. This was introduced in JDK 1.4.
13. Can we have statements between try, catch and finally blocks?
14. How are the keywords final, finally and finalize different from each other?
finally keyword: This is used in conjunction with the try-catch block or the try block where we
want to run some logic whether or not an exception has occurred.
finalize keyword: This is a method called by the Garbage Collector just before destroying the
objects no longer needed in the program.
int a = 30;
int b = 40;
int c = 10;
When the expression is evaluated, the denominator becomes zero. Hence Java would throw
ArithmeticException when it’s executed. The exception logs would be:
at TestClass.main(TestClass.java:8)
16. What is the difference between ClassNotFoundException and NoClassDefFoundError?
Both these exceptions occur when ClassLoader or JVM is not able to find classes while loading
during run-time. However, the difference between these 2 are:
ClassNotFoundException: This exception occurs when we try to load a class that is not found in the
classpath at runtime by making use of the loadClass() or Class.forName() methods.
NoClassDefFoundError: This exception occurs when a class was present at compile-time but was
not found at runtime.
This error is thrown by the compiler when we have multiple catch blocks and keep parent classes
first and subclasses later. The catch blocks should follow the order of the most specific ones at the
top to the most general ones at the bottom. If this is not followed, an unreachable catch block
error is thrown during compile time.
Exceptions in Java are hierarchical and follow inheritance to categorize different kinds of
exceptions. The parent class of all exceptions and errors is Throwable. This class has 2 child classes
- Error and Exception.
Errors are those abnormal failures that are not in the scope of recovery for the application. It is not
possible to anticipate errors or recover from them. Errors could be due to failures in hardware,
out-of-memory, JVM crash, etc.
Checked Exceptions are those that can be anticipated in the program at the time of compilation
and we should try to handle this otherwise it leads to a compilation error. IllegalAccessException,
ClassNotFoundException, and FileNotFoundException are some of the types of checked exceptions.
Exception is the parent class of all checked exceptions.
Unchecked exceptions are those exceptions that occur during runtime and are not possible to
identify at the time of compilation. These exceptions are caused due to mistakes in application
programming - for example, we try to access an element from an array index that is out of bounds
from the length of the array, while trying to run operations on null objects and so on.
RuntimeException, ArrayIndexOutOfBoundException, NullPointerException, ClassCastException,
NumberFormatException, IllegalArgumentException, etc are some of the types of unchecked
exceptions. The parent class of all runtime/unchecked exceptions is RuntimeException.
The exception hierarchy in Java has been depicted in the image below:
2. What does JVM do when an exception occurs in a program?
When there is an exception inside a method, the method creates and passes (throws) the
Exception object to the JVM. This exception object has information regarding the type of exception
and the program state when this error happens. JVM is then responsible for finding if there are any
suitable exception handlers to handle this exception by going backwards in the call stack until it
finds the right handler. If a matching exception handler is not found anywhere in the call stack,
then the JVM terminates the program abruptly and displays the stack trace of the exception.
When there is an exception thrown by the main() method if the exception is not handled, then the
program is terminated by the Java Runtime, and the exception message along with the stack trace
is printed in the system console.
We cannot throw a check exception from a static block. However, we can have try-catch logic that
handles the exception within the scope of that static block without rethrowing the exception using
the throw keyword. The exceptions cannot be propagated from static blocks because static blocks
are invoked at the compiled time only once and no method invokes these blocks.
6. What are different scenarios where “Exception in thread main” types of error could occur?
The following are some of the scenarios causing an exception in the main thread:
Exception in thread main java.lang.UnsupportedClassVersionError: This occurs when the Java class
is compiled from one JDK version and we run the class in another JDK version.
Exception in thread main java.lang.NoSuchMethodError: main: This occurs when we try to run a
class that has no main method.
Exception in thread main java.lang.NoClassDefFoundError: This occurs if a ClassLoader is unable to
find that class in the classpath at the time of loading it.
When there are exceptions that are to be thrown by the application, but the type is not
represented by any of the existing Exception types in Java, then we can provide more detailed
information by creating a custom exception. The creation of custom exceptions depends on the
business logic. While creating a custom exception, it is recommended to inherit from the most
specific Exception class that relates to the exception we want to throw. If there are no such classes
available, then we can choose the Exception class as the parent for this new custom exception.
Consider an example -
We want to access a file and return the first line of the file content.
} catch(FileNotFoundException fnfeException) {
In the above case, when there is an exception while reading the file - we do not know if it was
caused due to absence of the file or if the name of the file provided was wrong. To narrow this
down, we will create a custom exception called InvalidFileNameException by extending the
Exception class as shown below:
super(exceptionMessage);
To create a custom exception, we should also provide a constructor that makes a call to the parent
class constructor by using the super keyword. Our custom exception is ready. The code logic now
becomes:
} catch(FileNotFoundException fnfeException) {
if (!ifFileNameValid(fileName)) {
throw new InvalidFileNameException("Filename : " + fileName + " is invalid");
// Handle exception if the filename was valid and if the file is not found
import java.io.IOException;
import java.io.FileNotFoundException;
import javax.xml.bind.JAXBException;
try {
demoException();
} catch (IOException e) {
System.out.println(e.getMessage());
} catch (FileNotFoundException e) {
System.out.println(e.getMessage());
} catch (JAXBException e) {
System.out.println(e.getMessage());
We know that the FileNotFoundException is the subclass of IOException - By the rule of multiple
catch block, we need to have the most specific exception at the top and the most generic
exception at the bottom. If there are no parent-child relationships between the exceptions, they
can be placed anywhere. In this example, JAXBException is not related to IOException and
FileNotFoundException exceptions. Hence, it can be placed anywhere in the multiple catch block
structure. However, IOException being the parent class is mentioned at the beginning and that is
followed by FileNotFoundException. This results in an error - Unreachable catch block for
FileNotFoundException. It is already handled by the catch block for IOException. To fix this issue,
depending on the business requirements, we can either remove the FileNotFoundException from
the throws list and catch block OR we can rearrange the catch blocks as shown below:
try {
demoException();
} catch (FileNotFoundException e) {
System.out.println(e.getMessage());
} catch (IOException e) {
System.out.println(e.getMessage());
} catch (JAXBException e) {
System.out.println(e.getMessage());
9. Does the finally block always get executed in the Java program?
The finally blocks are meant to be executed whenever there is an exception or not in the try-catch
blocks. However, there is one scenario where this block does not get executed. It is when we
use System.exit(0) in either try or catch block. This is because the System.exit(0) terminates the
running JVM.
10. Why it is always recommended to keep the clean-up activities like closing the I/O resources or
DB connections inside a finally block?
When there is no explicit logic to terminate the system by using System.exit(0), finally block is
always executed irrespective of whether the exception has occurred or not. By keeping these
cleanup operations in the finally block, it is always ensured that the operations are executed and
the resources are closed accordingly. However, to avoid exceptions in the finally block, we need to
add a proper validation check for the existence of the resource and then attempt to clean up the
resources accordingly.
11. Are we allowed to use only try blocks without a catch and finally blocks?
Before Java 7, we were not allowed to use only try blocks. The try block should have been followed
by a catch or a finally block. But from Java 7 onwards, we can simply have a try block with a catch
or finally blocks in the form of try-with-resources that takes parameters implementing
the AutoCloseable interface. Note that, if the parameters do not implement
the AutoCloseable interface, then it leads to an error.
try{
demoMethod();
}catch(NullPointerException e){
System.out.println(e.getMessage());
}catch(Exception e){
System.out.println(e.getMessage());
foobar();
The program compiles successfully and it runs and displays nothing as no logic in both methods
could result in an exception.
If there are any exceptions in the demoMethod(), we can always catch the exception and handle it.
If the method foobar() declares NullPointerException using throws clause, the method doesn’t
need to throw an exception. However, if there is a logic that results in performing operations on
null objects inside the foobar() method, then NullPointerException will be thrown by the method
to the main() method. Since there is no exception handling for this foobar() method, the program
will terminate displaying the error message and stack trace.
list.forEach(i -> {
if (i < 0) {
System.out.println(i);
});
If we are using custom functional interfaces, then we can throw checked as well as unchecked
exceptions. Custom functional interfaces can be defined by using
the @FunctionalInterface keyword.
14. What are the rules we should follow when overriding a method throwing an Exception?
The following are some of the rules that have to be followed while overriding method throwing
Exception:
Rule 1: If the parent class method is not throwing any exceptions, then the overridden child class
method should not throw checked exceptions. But it can throw an unchecked exception. Consider
an example that demonstrates this- We have 2 classes - ParentDemo and ChildDemo where the
latter is the subclass of the ParentDemo class. We have the doThis() the method that is overridden
in the ChildDemo class. The overridden method may only throw an unchecked exception. The
below example is valid since IllegalArgumentException is an unchecked exception.
class ParentDemo {
void doThis() {
// ...
@Override
// ...
}
Rule 2: If the parent class method is throwing one or more checked exceptions, then the
overridden method in the child class can throw any unchecked exceptions or any exceptions that
are the same as checked exceptions of the parent method or the subclasses of those checked
exceptions. Consider the below example code:
class ParentDemo {
// ...
// ...
// ...
// ...
In this example, the doThis() method throws few exceptions than the parent method and
the doThat() method throws a greater number of exceptions, however, the scope of the exceptions
is not greater than the parent exceptions. If we try to throw a checked exception that was not
declared in the parent method or we throw an exception that has a broader scope, then it results
in a compilation error. For example, the below code is not valid as the parent method throws
a FileNotFoundException exception and the child method throws IOException which is broader in
scope as it is the parent class of FileNotFoundException:
class ParentDemo {
// ...
}
}
Rule 3: If the parent class method has a throws clause having unchecked exceptions, then the
overriding child method can throw any number of unchecked exceptions even if they are not
related to each other. Consider the below example. While the parent class doThis() method threw
only 1 unchecked exception which is IllegalArgumentException, the child class could throw
multiple unchecked exceptions as shown below:
class ParentDemo {
// ...
// ...
Rule 2: If the superclass method does not declare an exception, subclass overridden method
cannot declare the checked exception but can declare unchecked exception.
TestExceptionChild1.java
import java.io.*;
class Parent{
void msg() {
System.out.println("parent method");
}
}
try {
p.msg();
}
catch (Exception e){}
}
}
Output:
try {
p.msg();
}
catch(Exception e) {}
}
}
Output:
try {
p.msg();
}
catch(Exception e) {}
}
}
Output:
Example in case subclass overridden method declares no exception
TestExceptionChild5.java
import java.io.*;
class Parent {
void msg()throws Exception{
System.out.println("parent method");
}
}
try {
p.msg();
}
catch(Exception e) {}
}
}
Output:
Thread Questions
Process: It simply refers to a program that is in execution i.e., an active program. A process can be
handled using PCB (Process Control Block).
Thread Process
It is a program in execution containing multiple
It is a subset of a subunit of a process.
threads.
In this, inter-thread communication is faster, less
In this, inter-process communication is slower,
expensive, easy and efficient because threads share
expensive, and complex because each process
the same memory address of the process they
has different memory space or address.,
belong to.
These are easier to create, lightweight, and have less These are difficult to create, heavyweight, and
overhead. have more overhead.
It requires less time for creation, termination, and It requires more time for creation,
context switching. termination, and context switching.
Processes without threads use more
Processes with multiple threads use fewer resources.
resources.
Threads are parts of a process, so they are
dependent on each other but each thread executes Processes are independent of each other.
independently.
There is a need for synchronization in threads to There is no need for synchronization in each
avoid unexpected scenarios or problems. process.
They share data and information with each other. They do not share data with each other.
5. What’s the difference between class lock and object lock?
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
}
}
}
6. What's the difference between User thread and Daemon thread?
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().
notifyAll(): It sends notifications and wakes up all threads and allows them to compete for the
object's monitor instead of a single thread.
10. Why wait(), notify(), and notifyAll() methods are present in Object class?
We know that every object has a monitor that allows the thread to hold a lock on the object. But
the thread class doesn't contain any monitors. Thread usually waits for the object’s monitor (lock)
by calling the wait() method on an object, and notify other threads that are waiting for the same
lock using notify() or notifyAll() method. Therefore, these three methods are called on objects
only and allow all threads to communicate with each that are created on that object.
11. What is Runnable and Callable Interface? Write the difference between them.
Both the interfaces are generally used to encapsulate tasks that are needed to be executed by
another thread. But there are some differences between them as given below:
Running Interface: This interface is basically available in Java right from the beginning. It is simply
used to execute code on a concurrent thread.
Callable Interface: This interface is basically a new one that was introduced as a part of the
concurrency package. It addresses the limitation of runnable interfaces along with some major
changes like generics, enum, static imports, variable argument method, etc. It uses generics to
define the return type of object.
public interface Runnable
{
public abstract void run();
}
public interface Callable<V>
{
V call() throws Exception;
}
Runnable Interface vs Callable Interface
Runnable Interface Callable Interface
It does not return any result and therefore, cannot It returns a result and therefore, can throw an
throw a checked exception. exception.
It cannot be passed to invokeAll method. It can be passed to invokeAll method.
It was introduced in JDK 5.0, so one cannot
It was introduced in JDK 1.0.
use it before Java 5.
It simply belongs to Java.lang. It simply belongs to java.util.concurrent.
It uses the run() method to define a task. It uses the call() method to define a task.
To use this interface, one needs to override the run() To use this interface, one needs to override
method. the call() method.
12. What is the start() and run() method of Thread class?
start(): In simple words, the start() method is used to start or begin the execution of a newly
created thread. When the start() method is called, a new thread is created and this newly created
thread executes the task that is kept in the run() method. One can call the start() method only
once.
run(): In simple words, the run() method is used to start or begin the execution of the same
thread. When the run() method is called, no new thread is created as in the case of the start()
method. This method is executed by the current thread. One can call the run() method multiple
times.
The above diagram shows a deadlock situation where two threads are blocked forever. Thread 1 is
holding Object 1 but needs object 2 to complete processing whereas Thread 2 is holding Object 2
but needs object 1 first. In such conditions, both of them will hold lock forever and will never
complete tasks.
17. Explain volatile variables in Java?
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.
18. How do threads communicate with each other?
Threads can communicate using three methods i.e., wait(), notify(), and notifyAll().
19. Can two threads execute two methods (static and non-static concurrently)?
Yes, it is possible. If both the threads acquire locks on different objects, then they can execute
concurrently without any problem.
20. What is the purpose of the finalize() method?
Finalize() method is basically a method of Object class specially used to perform cleanup
operations on unmanaged resources just before garbage collection. It is not at all intended to be
called a normal method. After the complete execution of finalize() method, the object gets
destroyed automatically.
Synchronized Block: In this method, the thread acquires a lock on the object between parentheses
after the synchronized keyword, and releases the lock when they leave the block. No other thread
can acquire a lock on the locked object unless and until the synchronized block exists. It can be
used when one wants to keep other parts of the programs accessible to other threads.
Example:
package org.arpit.java2blog;
import java.util.concurrent.ArrayBlockingQueue;
import java.util.concurrent.BlockingQueue;
producerThread.start();
consumerThread.start();
BlockingQueue<String> queue=null;
public Producer(BlockingQueue queue) {
super();
this.queue = queue;
}
@Override
public void run() {
try {
System.out.println("Producing element 1");
queue.put("Element 1");
Thread.sleep(1000);
System.out.println("Producing element 2");
queue.put("Element 2");
Thread.sleep(1000);
System.out.println("Producing element 3");
queue.put("Element 3");
} catch (InterruptedException e) {
e.printStackTrace();
}
}
}
BlockingQueue<String> queue=null;
@Override
public void run() {
while(true)
{
try {
System.out.println("Consumed "+queue.take());
} catch (InterruptedException e) {
e.printStackTrace();
}
}
}
}
}
Output:
Producing element 1
Consumed Element 1
Producing element 2
Consumed Element 2
Producing element 3
Consumed Element 3
6. Can you start a thread twice?
No, it's not at all possible to restart a thread once a thread gets started and completes its
execution. Thread only runs once and if you try to run it for a second time, then it will throw a
runtime exception i.e., java.lang.IllegalThreadStateException.
Example:
public class TestThreadTwice1 extends Thread{
public void run(){
System.out.println(" thread is executing now........");
}
public static void main(String args[]){
TestThreadTwice1 t1=new TestThreadTwice1();
t1.start();
t1.start();
}
}
Output:
thread is executing now........
Exception in thread "main" java.lang.IllegalThreadStateException
7. Explain context switching.
Context switching is basically an important feature of multithreading. It is referred to as switching
of CPU from one thread or process to another one. It allows multiple processes to share the same
CPU. In context switching, the state of thread or process is stored so that the execution of the
thread can be resumed later if required.
8. What is CyclicBarrier and CountDownLatch?
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.
9. What do you mean by inter-thread communication?
Inter-thread communication, as the name suggests, is a process or mechanism using which
multiple threads can communicate with each other. It is especially used to avoid thread polling in
java and can be obtained using wait(), notify(), and notifyAll() methods.
10. What is Thread Scheduler and Time Slicing?
Thread Scheduler: It is a component of JVM that is used to decide which thread will execute next if
multiple threads are waiting to get the chance of execution. By looking at the priority assigned to
each thread that is READY, the thread scheduler selects the next run to execute. To schedule the
threads, it mainly uses two mechanisms: Preemptive Scheduling and Time slicing scheduling.
Time Slicing: It is especially used to divide CPU time and allocate them to active threads. In this,
each thread will get a predefined slice of time to execute. When the time expires, a particular
thread has to wait till other threads get their chances to use their time in a round-robin fashion.
Every running thread will get executed for a fixed time period.
11. What is a shutdown hook?
A shutdown hook is simply a thread that is invoked implicitly before JVM shuts down. It is one of
the most important features of JVM because it provides the capacity to do resource cleanup or
save application state JVM shuts down. By calling the halt(int) method of the Runtime class, the
shutdown hook can be stopped. Using the following method, one can add a shutdown hook.
public void addShutdownHook(Thread hook){}
Runtime r=Runtime.getRuntime();
r.addShutdownHook(new MyThread());
12. What is busy spinning?
Busy Spinning, also known as Busy-waiting, is a technique in which one thread waits for some
condition to happen, without calling wait or sleep methods and releasing the CPU. In this
condition, one can pause a thread by making it run an empty loop for a certain time period, and it
does not even give CPY control. Therefore, it is used to preserve CPU caches and avoid the cost of
rebuilding cache.
13. What is ConcurrentHashMap and Hashtable? In java, why is ConcurrentHashMap considered
faster than Hashtable?
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.
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
16. What is semaphore?
Semaphore is regarded as a thread synchronization construct that is usually required to control
and manage the access to the shared resource using counters. It simply sets the limit of the
thread. The semaphore class is defined within the package java.util.concurrent and can be used to
send signals between threads to avoid missed signals or to guard critical sections. It can also be
used to implement resource pools or bounded collection.
17. Explain Thread Group. Why should we not use it?
ThreadGroup is a class that is used to create multiple groups of threads in a single object. This
group of threads is present in the form of three structures in which every thread group has a
parent except the initial thread. Thread groups can contain other thread groups also. A thread is
only allowed to have access to information about its own thread group, not other thread groups.
Previously in the old version of Java, the only functionality that did not work without a thread
group was uncaughtException( Thread t, Throwable e). But now in Java 5 versions, there is
Thread.setUncaughtExceptionHandler(UncaughtExceptionHandler). So now even that works
without thread groups and therefore, there is no need to use thread groups.
t1.setUncaughtExceptionHandler(new UncaughtExceptionHandler()
{
@Override
public void uncaughtException(Thread t, Throwable e)
{
System.out.println("exception occured:"+e.getMessage());
}
};
18. What is the ExecutorService interface?
ExecutorService interface is basically a sub-interface of Executor interface with some additional
methods or features that help in managing and controlling the execution of threads. It enables us
to execute tasks asynchronously on threads.
Example:
import java.util.concurrent.ExecutorService;
import java.util.concurrent.Executors;
import java.util.concurrent.TimeUnit;
try {
e.submit(new Thread());
System.out.println("Shutdown executor");
e.shutdown();
e.awaitTermination(5, TimeUnit.SECONDS);
} catch (InterruptedException ex) {
System.err.println("tasks interrupted");
} finally {
if (!e.isTerminated()) {
System.err.println("cancel non-finished tasks");
}
e.shutdownNow();
System.out.println("shutdown finished");
}
}
try {
Long duration = (long) (Math.random() * 20);
System.out.println("Running Task!");
TimeUnit.SECONDS.sleep(duration);
} catch (InterruptedException ex) {
ex.printStackTrace();
}
}
}
}
Output:
Shutdown executor
shutdown finished
19. What will happen if we don’t override the thread class run() method?
Nothing will happen as such if we don’t override the run() method. The compiler will not show any
error. It will execute the run() method of thread class and we will just don’t get any output because
the run() method is with an empty implementation.
Example:
class MyThread extends Thread {
//don't override run() method
}
public class DontOverrideRun {
public static void main(String[] args) {
System.out.println("Started Main.");
MyThread thread1=new MyThread();
thread1.start();
System.out.println("Ended Main.");
}
}
Output:
Started Main.
Ended Main.
20. What is the lock interface? Why is it better to use a lock interface rather than a synchronized
block.?
Lock interface was introduced in Java 1.5 and is generally used as a synchronization mechanism to
provide important operations for blocking.