Java Multithreading
Java Multithreading
Java Multithreading
Uday Sharma
In a nut shell.......
• threads use shared memory area
• threads = faster content switching
• A thread is light-weight where a process is heavyweight
for example = A word processor can have one thread running in foreground as an editor and
another in the background auto saving the document !
• Flow of control in java
• Without threading :
• With threading :
• Creating a Threading:-
There are two ways to create a thread in java
1. By extending thread class .
2. By implementing Runnable interface .
• Advantages of Java Multithreading: -
1) It doesn't block the user because threads are independent and you can perform multiple
operations at the same time.
2) You can perform many operations together, so it saves time.
3) Threads are independent, so it doesn't affect other threads if an exception occurs in a single
thread.
2 • Multitasking
Multitasking is a process of executing multiple tasks simultaneously. We use multitasking to
utilize the CPU. Multitasking can be achieved in two ways:
• Process-based Multitasking (Multiprocessing).
• Thread-based Multitasking (Multithreading).
1) Process-based Multitasking (Multiprocessing):-
• Each process has an address in memory. In other words, each process allocates a separate
memory area.
• A process is heavyweight.
• Cost of communication between the process is high.
• Switching from one process to another requires some time for saving and loading registers,
memory maps, updating lists, etc.
2) Thread-based Multitasking (Multithreading):-
• Threads share the same address space.
• A thread is lightweight.
• Cost of communication between the thread is low.
Note: At least one process is required for each thread.
• What is Thread in java:-
A thread is a lightweight subprocess, the smallest unit of processing. It is a separate path of
execution.
Threads are independent. If there occurs exception in one thread, it doesn't affect other threads. It
uses a shared memory area.
As shown in the above figure, a thread is executed inside the process. There is context-switching
between the threads. There can be multiple processes inside the OS, and one process can have
multiple threads.
Note: At a time one thread is executed only.
3 • Java Thread class:-
Java provides Thread class to achieve thread programming. Thread class provides constructors
and methods to create and perform operations on a thread. Thread class extends Object class and
implements Runnable interface.
• Creating a Thread by Extending Thread class
• Multithreading In Java:-
• Multithreading shows the concurrency. Concurrency is task of running and managing
the multiple computation at the same time. While parallelism is the task of running
multiple computation simultaneously. concurrency can be done by using a sinlge
processing unit.
• Used to maximize the CPU utilization.
• We don't want our CPU to be in a free state; for example, Func1() comes into the memory
and demands any input/output process. The CPU will need to wait for unit Func1() to
complete its input/output operation in such a condition. But, while Func1() completes
its I/O operation, the CPU is free and not executing any thread. So, the efficiency of the
CPU is decreased in the absence of multithreading.
• In the case of multithreading, if a thread demands any I/O operation, then the CPU will
let the thread perform its I/O operation, but it will start the execution of a new thread
parallelly. So, in this case, two threads are executing at the same time.
1. Without threading:
class ThreadExample{
public static void main(String[] args) {
Func1();
Func2();
}
}
In the above code, you can see that Func1() and Func2() are called inside the main() function. But
the execution of Func2() will start only after the completion of the Func1().
2. With threading:-
Again, Func1() and Func2() are called inside the main function, but none of the two functions is
waiting for the execution of the other function. Both the functions are getting executed
concurrently.
• Ways To Create A Thread In Java:-
1. By extending the thread class
2. By implementing a Runnable interface
4
Let's see how we can create a thread by extending the thread class.
• Extending Thread Class :- (using the “ extends” and “Thread” keywords)
To create a thread using the thread class, we need to extend the thread class. Java's
multithreading system is based on the thread class.
• In the above code, we're first inheriting the Thread class and then overriding the run()
method.
• The code you want to execute on the thread's execution goes inside the run() method.
Code:-
Output:-
• We have to make a object of the runnable class , then declared the object as the thread the
using the start() method we access the both the threads of the runnable interface
simultaneously .
• Java Thread Life Cycle:-
6
In Java, a thread always exists in any one of the following states. These states are:
1. New
2. Active
3. Blocked / Waiting
4. Timed Waiting
5. Terminated
1). New - Whenever a new thread is created, it is always in the new state. For a thread in the new
state, the code has not been run yet and thus has not begun its execution.
Ex:- Instance of thread created which is not yet started by involving start(). In this state, the thread
is also known as the born thread.
2). Active: -When a thread invokes the start() method, it moves from the new state to the active
state. The active state contains two states within it: one is runnable, and the other is running.
3). Runnable - A thread, that is ready to run is then moved to the runnable state. In the
runnable state, the thread may be running or may be ready to run at any given instant of time. It is
the duty of the thread scheduler to provide the thread time to run, i.e., moving the thread the
running state.
Ex:-After invocation of start()& before it is selected to be run by the scheduler.
4). Running - When the thread gets the CPU, it moves from the runnable to the running state.
Generally, the most common change in the state of a thread is from runnable to running and again
back to runnable. After the thread scheduler has selected it.
Blocked or Waiting: -Whenever a thread is inactive for a span of time (not permanently) then,
either the thread is in the blocked state or is in the waiting state.
Timed Waiting: Sometimes, waiting for leads to starvation. For example, a thread (its name is
A) has entered the critical section of a code and is not willing to leave that critical section. In such
a scenario, another thread (its name is B) has to wait forever, which leads to starvation. To avoid
such scenario, a timed waiting state is given to thread B. Thus, thread lies in the waiting state for a
specific span of time, and not forever. A real example of timed waiting is when we invoke the
sleep() method on a specific thread. The sleep() method puts the thread in the timed wait state.
After the time runs out, the thread wakes up and start its execution from when it has left earlier.
5).Non-runnable - thread alive, not eligible to run.
6). Terminated - run() method has exited.
The following diagram shows the different states involved in the life cycle of a thread.
7
t1 0
t2 1
t3 2
t4 3
In the above table, we can see that Thread t1 has arrived first, then Thread t2, then t3, and at last t4,
and the order in which the threads will be processed is according to the time of arrival of threads.
Hence, Thread t1 will be processed first, and Thread t4 will be processed last.
Time-slicing scheduling:
Usually, the First Come First Serve algorithm is non-preemptive, which is bad as it may lead to
infinite blocking (also known as starvation). To avoid that, some time-slices are provided to the
threads so that after some time, the running thread has to give up the CPU. Thus, the other waiting
threads also get time to run their job.
9
In the above diagram, each thread is given a time slice of 2 seconds. Thus, after 2 seconds, the first
thread leaves the CPU, and the CPU is then captured by Thread2. The same process repeats for the
other threads too.
• Preemptive-Priority Scheduling:
The name of the scheduling algorithm denotes that the algorithm is related to the priority of the
threads.
Suppose there are multiple threads available in the runnable state. The thread scheduler picks that
thread that has the highest priority. Since the algorithm is also preemptive, therefore, time slices
are also provided to the threads to avoid starvation. Thus, after some time, even if the highest
priority thread has not completed its job, it has to release the CPU because of preemption.
• Working of the Java Thread Scheduler
10
Let's understand the working of the Java thread scheduler. Suppose, there are five threads that have
different arrival times and different priorities. Now, it is the responsibility of the thread scheduler to
decide which thread will get the CPU first.
The thread scheduler selects the thread that has the highest priority, and the thread begins the
execution of the job. If a thread is already in runnable state and another thread (that has higher
priority) reaches in the runnable state, then the current thread is pre-empted from the processor,
and the arrived thread with higher priority gets the CPU time.
When two threads (Thread 2 and Thread 3) having the same priorities and arrival time, the
scheduling will be decided on the basis of FCFS algorithm. Thus, the thread that arrives first gets
the opportunity to execute first.
• Thread.sleep() in Java:-
The Java Thread class provides the two variant of the sleep() method. First one accepts only an arguments,
whereas the other variant accepts two arguments. The method sleep() is being used to halt the working of a
thread for a given amount of time. The time up to which the thread remains in the sleeping state is known
as the sleeping time of the thread. After the sleeping time is over, the thread starts its execution from where
it has left.
• The sleep() Method Syntax:
Following are the syntax of the sleep() method.
1. public static void sleep(long mls) throws InterruptedException
2. public static void sleep(long mls, int n) throws InterruptedException
• The method sleep() with the one parameter is the native method, and the implementation of
the native method is accomplished in another programming language.
• The other methods having the two parameters are not the native method. That is, its
implementation is accomplished in Java. We can access the sleep() methods with the help
of the Thread class, as the signature of the sleep() methods contain the static keyword.
• The native, as well as the non-native method, throw a checked Exception. Therefore, either
try-catch block or the throws keyword can work here.
• The Thread.sleep() method can be used with any thread. It means any other thread or the
main thread can invoke the sleep() method.
Parameters:
The following are the parameters used in the sleep() method.
• mls: The time in milliseconds is represented by the parameter mls. The duration for which
the thread will sleep is given by the method sleep().
• n: It shows the additional time up to which the programmer or developer wants the thread
11
to be in the sleeping state. The range of n is from 0 to 999999.
The method does not return anything.
• Important Points to Remember About the Sleep() Method:-
• Whenever the Thread.sleep() methods execute, it always halts the execution of the current
thread.
• Whenever another thread does interruption while the current thread is already in the sleep mode,
then the InterruptedException is thrown.
• If the system that is executing the threads is busy, then the actual sleeping time of the thread
is generally more as compared to the time passed in arguments. However, if the system
executing the sleep() method has less load, then the actual sleeping time of the thread is almost
equal to the time passed in the argument.
• In this the Thread t1 is starts and print 1 and the Thread t1 is going to sleep for 1000milisec
• Due to this the Thread Schedule picks the Thread t2 and t2 is invoked by the start method and
print the 1
• And then Thread t2 goes to sleep for 1000msec , Then again the Thread Schedule picks the
Thread t1 and print the next number 2
• And This is process continues until all the number is printed:-
• And we can see in the output that the number printed is 1 ,1,2,2,3,3,4,4 .
• Because when t1 ,t2 Thread runs then the Thread is in sleep for 1sec and the number printed like
1,1 and 2,2 are printed in the 1sec gap.
• If we give the Negative time to the Thread than its give the error:-
“java.lang.IllegalArgumentException: timeout value is negative”
Code:-
12
As we can see in the above program that there is no context-switching because here t1 and t2 will
be treated as normal object not thread object.
In this the t1 and t2 is Treated as object which run the method name run() , it will not Treats as
Thread .
So in this t1.run() compiles first and gives the output then the t2.run() compiles and gives the
output.
• Java join() method:-
The join() method in Java is provided by the java.lang.Thread class that permits one thread to wait
until the other thread to finish its execution. Suppose th be the object the class Thread whose
thread is doing its execution currently, then the th.join(); statement ensures that th is finished
before the program does the execution of the next statement. When there are more than one thread
invoking the join() method, then it leads to overloading on the join() method that permits the
developer or programmer to mention the waiting period. However, similar to the sleep() method in
Java, the join() method is also dependent on the operating system for the timing, so we should not
14
assume that the join() method waits equal to the time we mention in the parameters. The following
are the three overloaded join() methods.
• Description of The Overloaded join() Method:-
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:
1. public final void join() throws InterruptedException
join(long mls, int nanos): When the join() method is invoked, the current thread stops its
execution and go into the wait state. The current thread remains in the wait state until the thread
on which the join() method is invoked called is dead or the wait for the specified time frame(in
milliseconds + nanos) is over.
Syntax:
1. public final synchronized void join(long mls, int nanos) throws InterruptedException, w
here mls is in milliseconds.
Code:-
15
Output:-
Another Example:-
Output:-
16
Output:-
17
Output:-
• As we can see in the output the Thread-0(which is t1 Thread) has the Highest priority and the
Thread-1 (which is t2 Thread) has the lowest priority.
• So we can see the Highest priority Thread run first then the Other priority Thread
• In the output the Thread-0 is highest, then Thread-2 then Thread-1 .
• We can see that Thread-0 runs first then Thread-2 then Thread-1 . and takes 1000milisec sleep
then run the other part of its Thread.
Note:-If you set the priority Greater than 10 its gives the error on a console .
• Daemon Thread in Java:-
Daemon thread in Java is a service provider thread that provides services to the user thread. Its life
depend on the mercy of user threads i.e. when all the user threads dies, JVM terminates this thread
automatically.
There are many java daemon threads running automatically e.g. gc, finalizer etc.
You can see all the detail by typing the jconsole in the command prompt. The jconsole tool provides
information about the loaded classes, memory usage, running threads etc.
19 • Points to remember for Daemon Thread in Java:-
o It provides services to user threads for background supporting tasks. It has no role in life than to serve
user threads.
o Its life depends on user threads.
o It is a low priority thread.
• Why JVM terminates the daemon thread if there is no user thread?
The sole purpose of the daemon thread is that it provides services to user thread for background
supporting task. If there is no user thread, why should JVM keep running this thread. That is why JVM
terminates the daemon thread if there is no user thread.
• Methods for Java Daemon thread by Thread class:-
The class provides two methods for java daemon thread.
1) public void setDaemon(boolean is used to mark the current thread as daemon thread or
status) user thread.
Output:-
Output:-
Explanation: It is evident by looking at the output of the program that tasks 4 and 5 are executed
only when the thread has an idle thread. Until then, the extra tasks are put in the queue.
The takeaway from the above example is when one wants to execute 50 tasks but is not willing to
create 50 threads. In such a case, one can create a pool of 10 threads. Thus, 10 out of 50 tasks are
assigned, and the rest are put in the queue. Whenever any thread out of 10 threads becomes idle, it
picks up the 11th task. The other pending tasks are treated the same way.
• Risks involved in Thread Pools:-
The following are the risk involved in the thread pools.
• Deadlock: It is a known fact that deadlock can come in any program that involves
multithreading, and a thread pool introduces another scenario of deadlock. Consider a scenario
where all the threads that are executing are waiting for the results from the threads that are
blocked and waiting in the queue because of the non-availability of threads for the execution.
• Thread Leakage: Leakage of threads occurs when a thread is being removed from the pool to
execute a task but is not returning to it after the completion of the task. For example, when a
thread throws the exception and the pool class is not able to catch this exception, then the
thread exits and reduces the thread pool size by 1. If the same thing repeats a number of times,
then there are fair chances that the pool will become empty, and hence, there are no threads
available in the pool for executing other requests.
• Resource Thrashing: A lot of time is wasted in context switching among threads when the size
of the thread pool is very large. Whenever there are more threads than the optimal number may
cause the starvation problem, and it leads to resource thrashing.
• Points to Remember:-
Do not queue the tasks that are concurrently waiting for the results obtained from the other tasks.
It may lead to a deadlock situation, as explained above.
Care must be taken whenever threads are used for the operation that is long-lived. It may result in
the waiting of thread forever and will finally lead to the leakage of the resource.
In the end, the thread pool has to be ended explicitly. If it does not happen, then the program
continues to execute, and it never ends. Invoke the shutdown() method on the thread pool to
terminate the executor. Note that if someone tries to send another task to the executor after
shutdown, it will throw a RejectedExecutionException.
One needs to understand the tasks to effectively tune the thread pool. If the given tasks are
contrasting, then one should look for pools for executing different varieties of tasks so that one can
properly tune them.
To reduce the probability of running JVM out of memory, one can control the maximum threads that
can run in JVM. The thread pool cannot create new threads after it has reached the maximum limit.
A thread pool can use the same used thread if the thread has finished its execution. Thus, the time
and resources used for the creation of a new thread are saved.
22 • Tuning the Thread Pool:-
The accurate size of a thread pool is decided by the number of available processors and the type of
tasks the threads have to execute. If a system has the P processors that have only got the
computation type processes, then the maximum size of the thread pool of P or P + 1 achieves the
maximum efficiency. However, the tasks may have to wait for I/O, and in such a scenario, one has to
take into consideration the ratio of the waiting time (W) and the service time (S) for the request;
resulting in the maximum size of the pool P * (1 + W / S) for the maximum efficiency.
• Conclusion:-
A thread pool is a very handy tool for organizing applications, especially on the server-side. Concept-
wise, a thread pool is very easy to comprehend. However, one may have to look at a lot of issues when
dealing with a thread pool. It is because the thread pool comes with some risks involved it (risks are
discussed above).
• ThreadGroup in Java:-
• Java provides a convenient way to group multiple threads in a single object. In such a way, we
can suspend, resume or interrupt a group of threads by a single method call.
Note: Now suspend(), resume() and stop() methods are deprecated.
• Java thread group is implemented by java.lang.ThreadGroup class.
• A ThreadGroup represents a set of threads. A thread group can also include the other thread
group. The thread group creates a tree in which every thread group except the initial thread group
has a parent.
• A thread is allowed to access information about its own thread group, but it cannot access the
information about its thread group's parent thread group or any other thread groups.
• Constructors of ThreadGroup class:-
There are only two constructors of ThreadGroup class.
2) ThreadGroup(ThreadGroup parent, String creates a thread group with a given parent group
name) and name.
1) void checkAccess() This method determines if the currently running thread has
permission to modify the thread group.
4) void destroy() This method destroys the thread group and all of its
subgroups.
23 5) int enumerate(Thread[] This method copies into the specified array every active
list) thread in the thread group and its subgroups.
6) int getMaxPriority() This method returns the maximum priority of the thread
group.
7) String getName() This method returns the name of the thread group.
8) ThreadGroup getParent() This method returns the parent of the thread group.
9) void interrupt() This method interrupts all threads in the thread group.
10) boolean isDaemon() This method tests if the thread group is a daemon thread
group.
11) void setDaemon(boolean This method changes the daemon status of the thread
daemon) group.
12) boolean isDestroyed() This method tests if this thread group has been destroyed.
13) void list() This method prints information about the thread group to
the standard output.
14) boolean parentOf(ThreadGro This method tests if the thread group is either the thread
up g group argument or one of its ancestor thread groups.
15) void suspend() This method is used to suspend all threads in the thread
group.
16) void resume() This method is used to resume all threads in the thread
group which was suspended using suspend() method.
17) void setMaxPriority(int This method sets the maximum priority of the group.
pri)
18) void stop() This method is used to stop all threads in the thread group.
19) String toString() This method returns a string representation of the Thread
group.
Code:- Simple Thread Group Example:-
Now all 4 threads belong to one group. Here, tg1 is the thread group name, MyRunnable is the class
that implements Runnable interface and "one", "two","three"and “fourth” are the thread names.
Now we can interrupt all threads by a single line of code only.
Thread.currentThread().getThreadGroup().interrupt();
24
Output:-
And There are my other Method in the Thread Group of Multithreading in Java like:-
• destroy()
• enumerate()
• getMaxPriority()
• ThreadGroup getParent()
• interrupt()
• isDaemon()
• isDestroyed()
• Java Shutdown Hook:-
• A special construct that facilitates the developers to add some code that has to be run when the
Java Virtual Machine (JVM) is shutting down is known as the Java shutdown hook. The Java
shutdown hook comes in very handy in the cases where one needs to perform some special
cleanup work when the JVM is shutting down. Note that handling an operation such as invoking
a special method before the JVM terminates does not work using a general construct when the
JVM is shutting down due to some external factors. For example, whenever a kill request is
generated by the operating system or due to resource is not allocated because of the lack of free
memory, then in such a case, it is not possible to invoke the procedure. The shutdown hook
solves this problem comfortably by providing an arbitrary block of code.
• Taking at a surface level, learning about the shutdown hook is straightforward. All one has to do
is to derive a class using the java.lang.Thread class, and then provide the code for the task one
wants to do in the run() method when the JVM is going to shut down. For registering the instance
26
of the derived class as the shutdown hook, one has to invoke the method
Runtime.getRuntime().addShutdownHook(Thread), whereas for removing the already
registered shutdown hook, one has to invoke the removeShutdownHook(Thread) method.
In nutshell, the shutdown hook can be used to perform cleanup resources or save the state when
JVM shuts down normally or abruptly. Performing clean resources means closing log files, sending
some alerts, or something else. So if you want to execute some code before JVM shuts down, use the
shutdown hook.
• When does the JVM shut down?
The JVM shuts down when:
o user presses ctrl+c on the command prompt
o System.exit(int) method is invoked
o user logoff
o user shutdown etc.
• The addShutdownHook(Thread hook) method:-
The addShutdownHook() method of the Runtime class is used to register the thread with the Virtual
Machine.
Syntax:
1. public void addShutdownHook(Thread hook){}
The object of the Runtime class can be obtained by calling the static factory method getRuntime().
For example:
Runtime r = Runtime.getRuntime();
• The removeShutdownHook(Thread hook) method:-
The removeShutdownHook() method of the Runtime class is invoked to remove the registration of
the already registered shutdown hooks.
Syntax:
1. public boolean removeShutdownHook(Thread hook){ }
True value is returned by the method, when the method successfully de-register the registered
hooks; otherwise returns false.
• Factory method:-
The method that returns the instance of a class is known as factory method.
Code:-Simple example of Shutdown Hook:-
Output:-
27
• By nulling a reference:
1. Employee e=new Employee();
2. e=null;
2) By assigning a reference to another:-
1. Employee e1=new Employee();
2. Employee e2=new Employee();
3. e1=e2;//now the first object referred by e1 is available for garbage collection
28
3) By anonymous object:-
1. new Employee();
• finalize() method:-
The finalize() method is invoked each time before the object is garbage collected. This method can
be used to perform cleanup processing. This method is defined in Object class as:
protected void finalize(){}
• Note: The Garbage collector of JVM collects only those objects that are created by new
keyword. So if you have created any object without new, you can use finalize method to
perform cleanup processing (destroying remaining objects).
gc() method:-
The gc() method is used to invoke the garbage collector to perform cleanup processing. The gc() is
found in System and Runtime classes.
1. public static void gc(){}
• Note: Garbage collection is performed by a daemon thread called Garbage Collector(GC). This
thread calls the finalize() method before object is garbage collected.
Code:-
Output:-
This Topics Cover Are look like in the Manner of Eclipse IDE ,JDK-18 , JAVA EE.
30
➢ Go check out my LinkedIn profile for more notes and other resources content
@Uday Sharma
mrudaysharma4600@gmail.com
https://www.linkedin.com/in/uday-sharma-602b33267