Multithreading in Java
Multithreading in Java
1) It doesn't block the user because threads are independent and you can perform multiple
operations at the same time.
3) Threads are independent, so it doesn't affect other threads if an exception occurs in a single
thread.
4) Multithreading can significantly enhance the performance of applications by making better use of
multiple CPU cores. Each thread can run on a separate core, allowing for parallel processing and
faster execution of tasks.
5) In applications with a graphical user interface (GUI), multithreading can help keep the interface
responsive. Long-running tasks can be handled in the background by separate threads, preventing
the main thread from freezing and improving user experience.
6) Threads within the same process share the same memory and resources, which makes it easier to
share data between them without the need for complex inter-process communication mechanisms.
7) Using multiple threads can simplify the design of complex applications, allowing for more
modular and manageable code. For example, separate threads can be dedicated to different tasks,
such as network communication, file I/O, and computation.
8) Multithreading allows an application to continue processing while waiting for I/O operations to
complete. This leads to better utilization of CPU resources as threads can perform useful work
during I/O waits.
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.
Thread States:
o New: A thread that has been created but not yet started.
o Runnable: A thread that is ready to run and waiting for CPU time.
o Waiting: A thread that is waiting indefinitely for another thread to perform a particular
action.
o Timed Waiting: A thread that is waiting for another thread to perform an action for up to a
specified waiting time.
12) static void yield() It causes the currently executing thread object to
pause and allow other threads to execute
temporarily.
16) void destroy() It is used to destroy the thread group and all of
its subgroups.
20) boolean isinterrupted() It tests whether the thread has been interrupted.
21) static interrupted() It tests whether the current thread has been
boolean interrupted.
22) static int activeCount() It returns the number of active threads in the
current thread's thread group.
24) static holdLock() It returns true if and only if the current thread
boolean holds the monitor lock on the specified object.
25) static void dumpStack() It is used to print a stack trace of the current
thread to the standard error stream.
27) static int enumerate() It is used to copy every active thread's thread
group and its subgroup into the specified array.
29) ThreadGro getThreadGroup() It is used to return the thread group to which this
up thread belongs
31) void notify() It is used to give the notification for only one
thread which is waiting for a particular object.
33) void setContextClassLoader() It sets the context ClassLoader for the Thread.
34) ClassLoade getContextClassLoader() It returns the context ClassLoader for the thread.
r
36) static void setDefaultUncaughtExce It sets the default handler invoked when a thread
ptionHandler() abruptly terminates due to an uncaught
exception.
Thread 3 - Count: 1
Thread 1 - Count: 1
Thread 2 - Count: 1
Thread 3 - Count: 2
Thread 2 - Count: 2
Thread 1 - Count: 2
Thread 3 - Count: 3
Thread 2 - Count: 3
Thread 1 - Count: 3
Thread 3 - Count: 4
Thread 1 - Count: 4
Thread 2 - Count: 4
Thread 3 - Count: 5
Thread 2 - Count: 5
Thread 1 - Count: 5
Thread 1 finished.
Thread 3 finished.
Thread 2 finished.
All threads have finished.
Explanation
By extending the Thread class and overriding its run method to print a message five times with a one-
second delay in between, this Java programme illustrates multithreading.
Three instances of MyThread are generated and launched using the start function in the main class,
MultiThreadingExample, enabling them to operate concurrently. In order to guarantee that the main
thread waits for every thread to finish before issuing a final message stating that every thread has
finished, the join() method is employed.
The runnable interface has an undefined method run() with void as return type, and it takes in no
arguments. The method summary of the run() method is given below-
Method Description
public void run() This method takes in no arguments. When the object of a
class implementing Runnable class is used to create a
thread, then the run method is invoked in the thread
which executes separately.
The runnable interface provides a standard set of rules for the instances of classes which wish to
execute code when they are active. The most common use case of the Runnable interface is when we
want only to override the run method. When a thread is started by the object of any class which is
implementing Runnable, then it invokes the run method in the separately executing thread.
A class that implements Runnable runs on a different thread without subclassing Thread as it
instantiates a Thread instance and passes itself in as the target. This becomes important as classes
should not be subclassed unless there is an intention of modifying or enhancing the fundamental
behavior of the class.
Runnable class is extensively used in network programming as each thread represents a separate
flow of control. Also in multi-threaded programming, Runnable class is used. This interface is present
in java.lang package.
Implementing Runnable
It is the easiest way to create a thread by implementing Runnable. One can create a thread on any
object by implementing Runnable. To implement a Runnable, one has only to implement the run
method.
In this method, we have the code which we want to execute on a concurrent thread. In this method,
we can use variables, instantiate classes, and perform an action like the same way the main thread
does. The thread remains until the return of this method. The run method establishes an entry point
to a new thread.
The thread will execute the code which is mentioned in the run() method of the Runnable object
passed in its argument.
The runnable class is used to perform multi-thread programming, especially in server-side as a server
may be getting several requests from different clients. To tackle this in a fast and resource-efficient
way, we use multi-thread programming.
The following program shows a server program which creates a thread, then creates a socket and
waits for a client to connect to it and asks for an input string-
@Override
public void run() {
ServerSocket serverSocket = null;
while (true) {
try {
serverSocket = new ServerSocket(3333);
Socket clientSocket = serverSocket.accept();
BufferedReader inputReader = new BufferedReader(new InputStreamReader(clientSocket.
getInputStream()));
System.out.println("Client said :"+inputReader.readLine());
}
catch (IOException e) {
e.printStackTrace();
}finally{
try {
serverSocket.close();
} catch (IOException e) {
e.printStackTrace();
}
}
}
}
}
In this program, we are creating a socket for the client on a thread. Usually, different threads are
created in a server for different client requests. Though, it is not a good practice to make an
individual thread for each client if the compiler's ability to control per-thread memory is bad.
o By extending thread, there is overhead of additional methods, i.e. they consume excess or
indirect memory, computation time, or other resources.
o Since in Java, we can only extend one class, and therefore if we extend Thread class, then we
will not be able to extend any other class. That is why we should implement Runnable
interface to create a thread.
o Runnable makes the code more flexible as, if we are extending a thread, then our code will
only be in a thread whereas, in case of runnable, one can pass it in various executor services,
or pass it to the single-threaded environment.