Multithreading in Java allows multiple threads to run concurrently within a single program. In this chapter, we will learn the concepts, benefits, and implementation of multithreading.
Multithreading is a process of executing multiple threads simultaneously within a single program. A thread is the smallest unit of execution in a program, and multithreading allows multiple threads to share the same memory and resources while running concurrently. This improves the performance of programs by making better use of CPU resources and enables tasks such as background processing, parallel computation, and responsive user interfaces.
In Java, multithreading can be implemented by:
You can create a thread by extending the Thread class and overriding its run() method. The run() method contains the code that defines the thread’s task. After creating an object of the subclass, you start the thread using the start() method.
The syntax to implement multithreading using extending the Thread class is as follows:
The following example demonstrates creating a thread by extending the Thread class:
Output:
Thread running: 1 Thread running: 2 Thread running: 3 Thread running: 4 Thread running: 5
Explanation:
The run() method contains the code executed by the thread. Calling start() initiates a new thread and executes the run() method concurrently with the main thread.
Another way to create a thread is by implementing the Runnable interface and providing an implementation for the run() method. You then pass the Runnable object to a Thread object and call start(). This approach can be used when your class is already extending another class.
The syntax to implement multithreading by implementing the Runnable interface is as follows:
The following example demonstrates creating a thread by implementing Runnable:
Output:
Thread running: 1 Thread running: 2 Thread running: 3 Thread running: 4 Thread running: 5
Explanation:
By implementing Runnable, the thread’s task is defined in the run() method, and the thread is started by creating a Thread object with the Runnable instance. This approach allows better flexibility and supports multiple inheritance indirectly.
In Java, a thread goes through different states from its creation to its termination. To manage the threads in multithreading, it is important to understand the life cycle of a thread (or, a flow of the threads). The main states of a thread are:
The following image shows the thread life cycle:

Java provides the Thread class to implement multithreading. The Thread class includes constructors and methods to create, manage, and control threads. It extends the Object class and implements the Runnable interface that allows the threads to be executed concurrently.
The following are the Thread class methods used for multithreading:
| Modifier and Type | Method | Description |
|---|---|---|
| void | start() | It is used to start the execution of the thread. |
| void | run() | It is used to do an action for a thread. |
| static void | sleep() | It sleeps a thread for the specified amount of time. |
| static Thread | currentThread() | It returns a reference to the currently executing thread object. |
| void | join() | It waits for a thread to die. |
| int | getPriority() | It returns the priority of the thread. |
| void | setPriority() | It changes the priority of the thread. |
| String | getName() | It returns the name of the thread. |
| void | setName() | It changes the name of the thread. |
| long | getId() | It returns the ID of the thread. |
| boolean | isAlive() | It tests if the thread is alive. |
| static void | yield() | It causes the currently executing thread object to pause and allow other threads to execute temporarily. |
| void | suspend() | It is used to suspend the thread. |
| void | resume() | It is used to resume the suspended thread. |
| void | stop() | It is used to stop the thread. |
| void | destroy() | It is used to destroy the thread group and all of its subgroups. |
| boolean | isDaemon() | It tests if the thread is a daemon thread. |
| void | setDaemon() | It marks the thread as a daemon or a user thread. |
| void | interrupt() | It interrupts the thread. |
| boolean | isinterrupted() | It tests whether the thread has been interrupted. |
| static boolean | interrupted() | It tests whether the current thread has been interrupted. |
| static int | activeCount() | It returns the number of active threads in the current thread's thread group. |
| void | checkAccess() | It determines if the currently running thread has permission to modify the thread. |
| static boolean | holdLock() | It returns true if and only if the current thread holds the monitor lock on the specified object. |
| static void | dumpStack() | It is used to print a stack trace of the current thread to the standard error stream. |
| StackTraceElement[] | getStackTrace() | It returns an array of stack trace elements representing the stack dump of the thread. |
| static int | enumerate() | It is used to copy every active thread's thread group and its subgroup into the specified array. |
| Thread.State | getState() | It is used to return the state of the thread. |
| ThreadGroup | getThreadGroup() | It is used to return the thread group to which this thread belongs |
| String | toString() | It is used to return a string representation of this thread, including the thread's name, priority, and thread group. |
| void | notify() | It is used to give a notification for only one thread that is waiting for a particular object. |
| void | notifyAll() | It is used to give a notification to all waiting threads of a particular object. |
| void | setContextClassLoader() | It sets the context ClassLoader for the Thread. |
| ClassLoader | getContextClassLoader() | It returns the context ClassLoader for the thread. |
| Static Thread.UncaughtExceptionHandler | getDefaultUncaughtExceptionHandler() | It returns the default handler invoked when a thread abruptly terminates due to an uncaught exception. |
| static void | setDefaultUncaughtExceptionHandler() | It sets the default handler invoked when a thread abruptly terminates due to an uncaught exception. |
Multithreading is widely used in real-world applications to perform multiple tasks simultaneously. Here are two practical examples:
In online banking systems, multiple users can perform transactions like deposits, withdrawals, and fund transfers at the same time. Each transaction can run on a separate thread that allows the system to process multiple requests concurrently without delays.
The following code demonstrates multithreading in an online banking transaction:
Output:
Deposit started. Withdrawal started. Deposit completed. Withdrawal completed.
A web server can handle multiple client requests simultaneously by assigning each request to a separate thread. This ensures that the server remains responsive even when many clients are connected.
The following code demonstrates multithreading for a web server handling multiple clients:
Output:
Client1 request processing started. Client2 request processing started. Client1 request processing completed. Client2 request processing completed.
Here are some of the advantages of using multithreading:
We request you to subscribe our newsletter for upcoming updates.