Java_Multithreading
Java_Multithreading
Multithreading means multiple threads and is considered one of the most important features of Java. As the
name suggests, it is the ability of a CPU to execute multiple threads independently at the same time but share
the process resources simultaneously. Its main purpose is to provide simultaneous execution of multiple threads
to utilize the CPU time as much as possible. It is a Java feature where one can subdivide the specific program
into two or more threads to make the execution of the program fast and easy.
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.
Output:
Output:
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
These are easier to create, lightweight, and have These are difficult to create, heavyweight,
less overhead. and have more overhead.
It requires less time for creation, termination, and It requires more time for creation,
context switching. termination, and context switching.
Processes with multiple threads use fewer Processes without threads use more
resources. resources.
Threads are parts of a process, so they are Processes are independent of each other.
dependent on each other but each thread
Thread Process
executes independently.
They share data and information with each other. They do not share data with each other.
Example:
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:
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().
JVM waits for user threads to finish JVM does not wait for daemon threads to finish their tasks
their tasks before termination. before termination.
They are used for critical tasks or They are not used for any critical tasks but to do some
core work of an application. supporting tasks.
These threads are referred to as These threads are referred to as low priority threads,
high-priority tasks, therefore are therefore are especially required for supporting
required for running in the background tasks like garbage collection, releasing
foreground. memory of unused objects, etc.
Output:
t1 is Daemon thread
t3 is Daemon thread
t2 is User thread
But one can only call the setDaemon() method before start() method otherwise it will definitely throw
IllegalThreadStateException as shown below:
Output:
Thread name: Thread-0
Check if its DaemonThread: false
Example:
synchronized(monitor)
{
monitor.wait(); Here Lock Is Released by Current Thread
}
sleep(): As the name suggests, it is a static method that pauses or stops the execution of the current thread for
some specified period. It doesn’t release the lock while waiting and is mostly used to introduce pause on
execution. It is defined in thread class, and no need to call from a synchronized context.
Example:
synchronized(monitor)
{
Thread.sleep(1000); Here Lock Is Held by The Current Thread
//after 1000 milliseconds, the current thread will wake up, or after we call that is interrupt() method
}
9. What’s the difference between notify() and notifyAll()?
notify(): It sends a notification and wakes up only a single thread instead of multiple threads that are waiting on
the object’s monitor.
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.
It does not return any result and therefore, cannot It returns a result and therefore, can throw
throw a checked exception. an exception.
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 To use this interface, one needs to override
run() method. the call() method.
Improve performance as compared to traditional parallel programs that use multiple processes.
If an exception occurs in a single thread, it will not affect other threads as threads are independent.
16. Explain the meaning of the deadlock and when it can occur?
Deadlock, as the name suggests, is a situation where multiple threads are blocked forever. It generally occurs
when multiple threads hold locks on different resources and are waiting for other resources to complete their
task.
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.
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.
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.
Example:
package org.arpit.java2blog;
import java.util.concurrent.ArrayBlockingQueue;
import java.util.concurrent.BlockingQueue;
producerThread.start();
consumerThread.start();
}
static class Producer implements Runnable {
BlockingQueue<String> queue=null;
@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
Example:
Output:
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.
8. 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.
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.
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.
Synchronized blocks should be preferred more as it boosts the performance of a particular program. It only locks
a certain part of the program (critical section) rather than the entire method and therefore leads to less
contention.
Example:
Output:
10
33
10 33
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());
}
};
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
18. 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:
Output:
Started Main.
Ended Main.
19. 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.
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.
20. Is it possible to call the run() method directly to start a new thread?
No, it's not possible at all. You need to call the start method to create a new thread otherwise run method won't
create a new thread. Instead, it will execute in the current thread.
21. Is it possible that each thread can have its stack in multithreaded programming?
Of course, it is possible. In multithreaded programming, each thread maintains its own separate stack area in
memory because of which every thread is independent of each other rather than dependent.
By synchronized block
By static synchronization
Syntax:
synchronized (object)
{
//statement to be synchronized
}
Conclusion
1. Conclusion
Overall, multithreading is a very essential part of Java and modern software development. It is very helpful in
making the program more efficient and also reduces the usage of storage resources.