Multithreading In Java

Multithreading in Java refers to the capability of running numerous threads concurrently.

A thread is a compact subprocess, representing the smallest processing entity. Multiprocessing and multithreading are both techniques employed to accomplish multitasking.

We opt for multithreading over multiprocessing due to the utilization of a shared memory space by threads. Unlike processes, threads do not require distinct memory allocations, resulting in memory conservation. Additionally, the context-switching between threads is more efficient compared to that of processes.

Multithreading in Java is commonly employed in applications such as games, animations, and more.

Advantages of Java Multithreading

  • It does not block the user because threads are independent, and you can perform multiple operations at the same time.
  • You can perform many operations together, so it saves time.
  • Threads are independent , so it doesn't affect other threads if an exception occurs in a single thread.
  • 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.
  • 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.
  • 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.
  • 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.
  • Multithreading allows an application to continue processing while waiting for I/O operations to complete . It leads to better utilization of CPU resources as threads can perform useful work during I/O waits.
  • Multitasking

Multitasking involves running multiple tasks concurrently, allowing efficient CPU utilization. There are two main approaches to achieving multitasking:

  • Process-based Multitasking, also known as Multiprocessing
  • Thread-based Multitasking, which is referred to as 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 a thread in Java?

A thread is a slim subprocess, representing the most basic processing unit, functioning as an independent flow of execution.

Each thread operates autonomously. In the event of an exception in one thread, it does not impact the functionality of other threads. Threads share a common memory space.

Illustrated in the diagram above, a thread runs within a process, with context-switching occurring among the threads. The operating system can support several processes, each of which may contain multiple threads.

Note: At a time, one thread is executed.

Java Thread Class

In Java, thread programming is facilitated through the utilization of the Thread class. This class offers various constructors and functions to establish and manage thread-related tasks. It is an extension of the Object class and incorporates the implementation of the Runnable interface.

Thread States

Fresh: A thread that has been instantiated but has not commenced yet.

Runnable or Running: A thread in a state where it is prepared to execute and is waiting for its turn to be allocated CPU resources.

A "waiting" refers to a thread that is in a state of waiting indefinitely for another thread to execute a specific action.

Terminated: A thread that has completed its task.

Java Thread Class Methods

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.

Java Multithreading Example

Example

Example

class MyThread extends Thread {  

    private String threadName;  

    MyThread(String name) {  

        threadName = name;  

    }  

    // Override the run method to define the task for the thread  

    public void run() {  

        for (int i = 1; i <= 5; i++) {  

            System.out.println(threadName + " - Count: " + i);  

            try {  

                // Sleep for a while to simulate some work  

                Thread.sleep(1000);  

            } catch (InterruptedException e) {  

                System.out.println(threadName + " interrupted.");  

            }  

        }  

        System.out.println(threadName + " finished.");  

    }  

}  

public class Main {  

    public static void main(String[] args) {  

        // Create instances of MyThread  

        MyThread thread1 = new MyThread("Thread 1");  

        MyThread thread2 = new MyThread("Thread 2");  

        MyThread thread3 = new MyThread("Thread 3");  

        // Start the threads  

        thread1.start();  

        thread2.start();  

        thread3.start();  

        // Wait for all threads to finish  

        try {  

            thread1.join();  

            thread2.join();  

            thread3.join();  

        } catch (InterruptedException e) {  

            System.out.println("Main thread interrupted.");  

        }  

        System.out.println("All threads have finished.");  

    }  

}

Output:

Output

Thread 3 - Count: 1

Thread 1 - Count: 1

Thread 2 - Count: 1

Thread 1 - Count: 2

Thread 2 - Count: 2

Thread 3 - Count: 2

Thread 1 - Count: 3

Thread 2 - Count: 3

Thread 3 - Count: 3

Thread 1 - Count: 4

Thread 2 - Count: 4

Thread 3 - Count: 4

Thread 1 - Count: 5

Thread 2 - Count: 5

Thread 3 - Count: 5

Thread 2 finished.

Thread 1 finished.

Thread 3 finished.

All threads have finished.

Explanation

This Java program demonstrates multithreading by creating a subclass that extends the Thread class. In this subclass, the run method is overridden to output a message five times with a one-second interval between each message.

Three instances of MyThread are created and started within the Main class to enable them to run simultaneously. To ensure that the main thread waits for each of these threads to complete their execution before displaying a final message indicating the completion of all threads, the join method is utilized.

Advantages of Multithreading in Java

  • Enhanced Performance: Multithreading enables concurrent execution of multiple tasks, which decreases execution time and boosts efficiency overall.
  • Parallel Execution: Tasks like file processing, network operations, and calculations can occur simultaneously, enhancing the speed of applications.
  • Improved GUI Responsiveness: For applications with graphical user interfaces (GUIs), multithreading facilitates smooth interactions by managing user inputs independently from background tasks.
  • Better CPU Utilization: Threads can operate in parallel, optimizing the use of available CPU resources, particularly on multi-core processors.
  • Reduced Development Time: Multithreading breaks complex tasks into smaller, manageable threads, thereby decreasing the effort required for development.
  • Disadvantages of Multithreading in Java

  • Complexity: Compared to single-threaded systems, multithreaded applications are far more difficult to write, test, and debug.
  • Resource Overhead: As a result of creating too many threads, performance may suffer from excessive memory utilization and CPU context switching.
  • Problems with synchronization: Inadequate management of shared resources can result in issues like race situations, deadlocks, and inconsistent data.
  • Error Handling Difficulties: Errors in one thread may not spread to others easily, making it more difficult to identify and address problems.
  • Unpredictable Behaviour: If threads are not correctly synchronized, the CPU scheduler, which controls the threads' execution order, might cause unexpected results.
  • Java Multithreading MCQs

  1. Which of the following is not a valid way to create a thread in Java?
  • Extending the Thread class
  • Implementing the Runnable interface
  • Implementing the Callable interface
  • Implementing the Serializable interface

Explanation: Serializable is not related to threading. Threads can be created by extending Thread, implementing Runnable, or using Callable with FutureTask.

  1. What is a thread in Java?
  • A lightweight process that runs independently within a program
  • A block of code that runs concurrently with the main program
  • A method that can be called asynchronously
  • A Java class that extends the Thread class

Explanation: A thread is a lightweight process, the smallest unit of processing. It is a separate path of execution. Threads are independent. If an exception occurs in one thread, it does not affect other threads. It uses a shared memory area.

  1. Which of the following methods is used to start a new thread in Java?
  • execute
  • start
  • run
  • new

Explanation: The start method is used to start a new thread in Java.

  1. Which of the following is the correct sequence of thread states?
  • New, Running, Blocked, Terminated
  • Running, New, Blocked, Terminated
  • New, Running, Waiting, Terminated
  • Running, Blocked, Waiting, Terminated

Explanation: The order of thread states in the Java thread lifecycle is New, Runnable (or Running), Waiting, and Terminated.

  1. What happens when a thread calls the wait method?
  • It signals other threads to start executing.
  • It terminates immediately.
  • It waits until another thread calls notify or notifyAll on the same object.
  • It goes into a busy-wait loop.

When a thread invokes the wait method, it remains in a waiting state until another thread invokes notify or notifyAll on the same object to signal it to resume execution.

Input Required

This code uses input(). Please provide values below: