Blog

Multithreading in Java

  • (4.0)
  • | 353 Ratings

Multithreading is the basic concept of Object Oriented Programming which revolves around the real-life entities.

Multithreading in Java

Multithreading in Java is a process where multiple threads/tasks executed simultaneously. A thread is a lightweight, smallest sub-process. Threads are assigned shared memory area. They don’t have a separate memory area. So, this saves memory and context switching between threads will be faster than the process. This concept is mostly implemented in games and animation.

lifecycle of a Thread

Below are different stages of a thread lifecycle:

img

  • New: This is the first stage of any new born thread. Until the program starts the thread, thread remains in new state.
  • Runnable: Once it is invoked, thread will be in runnable state until it is picked up by scheduler to run.
  • Running: Once the thread scheduler selects the thread, its state will be changed from runnable to running.
  • Waiting: Thread will be in waiting state when it is alive but not eligible for running.
  • Dead: Once thread is existed or terminated, its state will change to dead.

Creating a Thread in Java

Before creating a thread in Java, let us first go through some important methods of the thread which we are going to use in the following examples.

Method Name Meaning
start() This method is responsible for starting the execution of thread.
Sleep(int milliseconds) This method is responsible for making thread sleep. While sleeping, thread’s execution will stop and resume after the milliseconds pause we have given. This is helpful for synchronization of threads.
getName() Returns the thread name
setPriority(int newpriority) This method is responsible for setting the priority of a thread.
run () It is a thread’s entry point.
getPriority() Returns a thread’s priority
isAlive() Returns true if thread is alive else false

Java has below 2 methods to create and use a thread.

Extend Thread class

Here, we need to create a class which is extending Thread class. The class which we have created must override run() method, which is the entry point for any new thread. Now we can access this class by creating an object of it. Through this object, we need to initiate start() method to initiate the execution of the thread. Below is the example for same.

class ThreadDemo extends Thread 
{ 
    public void run() 
    { 
        try
        { 
           System.out.println (Thread.currentThread().getName() + 
                  " is running"); 
  
        } 
        catch (Exception e) 
        { 
           System.out.println ("Into Thread Exception"); 
        } 
    } 
} 
  
 
public class Main 
{ 
    public static void main(String[] args) 
    { 
        int n = 5; 
        for (int i=0; i

Output:

Thread-0 Alive
Thread-0 is running
Thread-1 Alive
Thread-1 is running
Thread-2 Alive
Thread-2 is running
Thread-3 Alive
Thread-3 is running
Thread-4 Alive
Thread-4 is running

Implement Runnable interface

Here, we need to create a class which implements Runnable interface. Runnable interface needs run() method to be implemented in the class which implements Runnable interface. run() method will have code which creates a new thread. Once the class is prepared, we can instantiate that class and use the object of that class to start the execution of the thread. Below is an example for same.

class ThreadDemo implements Runnable
{
   Thread th ;
   ThreadDemo()
   { 
      th = new Thread(this, "Test Thread");
      System.out.println("Thread Created" + th);
      th.start();
   }
   public void run()
   {
      try
      {
        for (int i=0 ;i<5;i++)
        {
          System.out.println("Thread " + i);
          Thread.sleep(1500);
        }
     }
     catch(InterruptedException e)
     {
        System.out.println("Thread interrupted");
     }
     System.out.println("Exiting the thread" );
   }
}
public class Main
{
    public static void main(String args[])
    {
       new ThreadDemo();
    }
}

Output:

Thread CreatedThread[Test Thread,5,main]
Thread 0
Thread 1
Thread 2
Thread 3
Thread 4
Exiting the thread

Synchronization

Synchronization is the process to assure that the resources are only used by one thread at a time. If one resource is used by multiple threads, then that can create a deadlock situation. To avoid that, we need to implement synchronization in our code.

Java has provided the synchronized approach while writing the code to assure the behavior. So, when one thread enters the synchronized block, no other thread can enter the same method. All other threads need to wait until the first thread finishes the execution. Once it is finished, other threads can start their execution.

Let us see below example where multiple threads try to use same method.

class Demo {
    void call(String msg) {
        System.out.print("[" + msg);
        try {
                Thread.sleep(1000);
        } catch(InterruptedException e) {
                System.out.println("Interrupted");
        }
        System.out.println("]");
    }
}
 
class Test implements Runnable {
    String msg;
    Demo target;
    Thread t;
    public Test(Demo targ, String s) {
        target = targ;
        msg = s;
        t = new Thread(this);
        t.start();
    }
 
    public void run() {
        target.call(msg);
    }   
}
public class SynchronizeDemo {
    public static void main(String args[]) {
        Demo target = new Demo();
        Test ob1 = new Test(target, "Learn");
        Test ob2 = new Test(target, "Synchronized");
        Test ob3 = new Test(target, "Java");
        // wait for threads to end
        try {
            ob1.t.join();
            ob2.t.join();
            ob3.t.join();
        } catch(InterruptedException e) {
                System.out.println("Interrupted");
        }
    }
}

Output:

[Synchronized[Java[Learn]
]
]

Here we can see, call() method has switched execution to another thread and that is why we are getting mixed string as output. This is termed as race condition. Here 3 threads are racing with each other to complete their execution. Here output is not predictable as we are not aware and when context switch will happen. Due to this, program can run correctly at one time but wrong at next. 

To avoid this situation, we must restrict the access to call method by using the keyword synchronize in the method call like shown below:

synchronized void call(String msg)

If we modify above program and add synchronize keyword to call() method then the output will be like below:

[Learn]
[Java]
[Synchronized]

Subscribe For Free Demo

Free Demo for Corporate & Online Trainings.

Ravindra Savaram
About The Author

Ravindra Savaram is a Content Lead at Mindmajix.com. His passion lies in writing articles on the most popular IT platforms including Machine learning, DevOps, Data Science, Artificial Intelligence, RPA, Deep Learning, and so on. You can stay up to date on all these technologies by following him on LinkedIn and Twitter.


DMCA.com Protection Status

Close
Close