Select Page

Multithreading in Java – A Guide for Beginners

Joydip Kanjilal
Published: May 25, 2022

Java Developer Tutorials

Multithreading in Java applications allows multiple threads to run concurrently within a single process. Threads are independently executing tasks that can share data and other resources, such as files and network connections. In this Java programming tutorial, we will explore what Java multithreading is, its benefits, and downsides.

What is a Thread in Java?

A thread is a light-weight process that can be independently scheduled by the operating system. It is also defined as the independent path of execution within a program that allows for concurrent execution of code, meaning that multiple threads can execute concurrently.

Each thread has its own stack, meaning that it can have local variables and keep track of its own execution. Threads can be used to achieve parallelism, which is when multiple tasks are executed simultaneously.

In Java (and other programming languages), threads share the same address space and therefore have access to all variables, objects, methods and global scope of the application or program.

Read: Tips to Improve Java Performance

What is Multithreading in Java?

Multithreading is the ability of an operating system to have numerous threads in memory at the same point in time with the illusion that all these threads are executing concurrently. The operating system allocates a specific time slice to each “thread,” switching between them whenever their time slice expires. The process of switching between threads is known as context switch.

Context switching involves:

  • Storing the thread’s state.
  • Flushing out the CPU registers.
  • Passing CPU control to the next thread in the queue.

It should be noted that a processor can execute one and only one thread at any point in time. By starting multiple tasks at the same time, you can achieve better throughput as compared to running single-threaded applications when there are many tasks waiting for completion (like reading from disk).

What are the Advantages of Multithreading in Java?

Below is a list of some of the advantages of multithreading in Java:

  • Improved responsiveness
  • Faster execution
  • Better CPU and Memory utilization
  • Support for Concurrency

Disadvantages of Multithreading

The following are the drawbacks of using threads in your Java applications and software development practices:

  • Challenges in testing and debugging
  • Adds complexity to codebases

Read: Classes and Objects in Java

Multithreading in Java

The Java Programming Language has built-in support for working with multithreading. When you run a Java application, the Java Virtual Machine (JVM) creates a thread called the main thread. The main thread is responsible for running the application’s main() method. The main thread can then create other threads, which can run concurrently with the main thread.

Concurrent execution of threads can help improve the performance of your application by utilizing multiple CPUs or processors. It can also help improve responsiveness by allowing tasks to be executed in the background while the user interacts with the graphical user interface (GUI).

How to Program Multithreading in Java

You can create threads in Java in one of the following ways:

  • Extending the Thread class
  • Implementing the Runnable Interface

Extending the Thread Class in Java

The following program illustrates how you can implement multithreading in Java by extending the Thread class:

class MyThreadClass extends Thread {
    public void run()
    {
        try {
                System.out.println(
                "The Current Thread Id is:" + Thread.currentThread().getId());
        }
        catch (Exception ex) {
            System.out.println("An error occurred...");
        }
    }
}
public class MultithreadingDemo {
    public static void main(String[] args)
    {
        for (int i = 0; i < 5; i++) {
            MyThreadClass obj
                = new MyThreadClass();
            obj.start();
        }
    }
}

Implementing the Runnable Interface in Java

Runnable is an interface that allows you to create tasks that can be executed by a thread. A task is just a piece of code that can be run by a thread. You can think of it like a method that doesn’t have any return value and takes no parameters.

The following program shows how you can implement multithreading in Java by implementing the Runnable interface:

class MyThreadClass implements Runnable 
{
    public void run()
    {
        try 
        {
           System.out.println("Hello world");
        }
        catch (Exception ex) {
            System.out.println("An error occurred...");
        }
    }
}
public class MultithreadingDemo {
    public static void main(String[] args)
    {
        for (int i = 0; i < 5; i++) {
            Thread obj
                = new Thread(new MyThreadClass());
            obj.start();
        }
    }
}

Read: The Top Java IDEs and Code Editors

What is a Thread State in Java?

When a Java program starts up, there is only one thread – the main thread. This thread is responsible for executing the main() method of the program. Once the main() method exits, the program terminates. However, a Java program can have multiple threads running concurrently.

A thread can be in one of several states:

  • Ready or Runnable – This is a state at which the thread is waiting in the ready or runnable queue to be allocated the processor. A thread enters this state when you call the start method on the thread object. The thread relinquishes control to the next thread in the ready or runnable queue when the runtime calls the yield method implicitly.
  • Running – This is the state when the thread is being executed by the processor. The scheduler is responsible of scheduling the thread to the running state at an appropriate time – usually after its turn comes and the currently running thread has completed its execution.
  • Waiting/Suspended/Blocked – The thread enters the suspended state when you call the suspend method on the thread object. A suspended thread can be moved back to the running state after a call to the resume method. The thread waits for I/O when it is in the waiting state.

When a thread has completed its execution or has been terminated, it stops.

Thread Priority and Scheduling in Java

In Java, every thread has a priority, which is an integer value that defines how the scheduler prioritizes threads. The scheduler will always give preference to the thread with the higher priority, meaning that it is more likely to be executed sooner than a lower priority thread. A thread’s default priority is 5.

You can set a thread’s priority using the setPriority() method, which takes an integer between 1 and 10 as its parameter. The lower the number, the lower the priority; thus, a priority of 1 is the lowest priority while 10 is the highest. Below is an example of how to set a thread’s priority:

thread.setPriority(5);

When multiple threads have the same priority, their order of execution is dictated by when they were created (i.e., which one came first). This is known as First in First Out (FIFO) scheduling.

Final Thoughts on Multithreading in Java

Threads can be created in two ways: by extending the Thread class or by implementing the Runnable interface. Albeit all the benefits that multithreading has to offer, you must use it with caution. You should know how to handle thread synchronization issues and avoid deadlocks and race conditions. We will discuss more on multithreading in future articles here.

Read more Java programming tutorials and Java tool reviews.

Source: www.developer.com