Java

Java – Multithreading With Examples

Let’s examine threads first, then multithreading. A thread is the smallest, lightest component of a process that may operate simultaneously with other components (other threads) of the same process. Because each thread follows a unique route of execution, threads are autonomous, which explains why an error in one thread doesn’t influence how other threads are being run. A process’ common memory is shared by all of its threads. Multithreading is the process of running many threads concurrently.

Let’s list the main topics of the conversation:
1. To make the most of the CPU time, multithreading enables the simultaneous execution of two or more software components. A multithreaded program has two or more simultaneously running components. Such software components are referred to as threads.

2. The shared memory area is used by threads, which are little subprocesses. Programs that profit from multithreading use the most CPU time possible in a multithreaded environment to reduce idle time.

3. Any of the following states are possible for a thread:
NEW – A thread in this condition has not yet begun.
A thread running on the Java virtual machine is said to be in the state of “RUNNABLE.”
BLOCKED – This condition describes a thread that is stalled while awaiting a monitor lock.
WAITING – A thread in this state is one that is patiently waiting for another thread to complete a certain task.
TIMED WAITING – This state describes a thread that is awaiting another thread to act for a predetermined amount of time.
A thread that has terminated is in the condition of “TERMINATED.”
At any one moment, a thread can only be in one state.

Multitasking vs Multithreading vs Multiprocessing vs parallel processing

As they are used rather often when we discuss multithreading, if you are new to Java, you may get confused by these phrases. Let’s have a quick discussion on these.

Multitasking: The capacity to carry out many tasks at once is referred to as multitasking.

We’ve previously spoken about multitasking. It is a method of running many threads at once. Thread-based Multitasking is another name for multithreading.

Multiprocessing: This is similar to multitasking, but that many CPUs are used. On the other hand, multitasking is done by one CPU.

The term “parallel processing” describes the use of many CPUs inside a single computer system.

Creating a thread in Java

In Java, there are two methods for creating threads:
1) By extending the Thread class.
2) By using the interface Runnable.

Let’s have a look at these methods of the Thread class before we start writing the programs (code) for establishing threads. In the example below, we’ve employed a handful of these techniques.

getName(): It is utilized to get the thread name.

  • getPriority(): Obtain the priority of a thread.
  • isAlive():Check to see if a thread is still active
  • join():Observe for a thread to end
  • run(): beginning of the thread
  • sleep():For a while, put a thread on hold.
  • Call a thread’s run() method to start it.
  • Method 1: Thread creation by extending Thread class

Example 1:

class MultithreadingDemo extends Thread{  
  public void run(){  
    System.out.println("My thread is in running state.");  
  }   
  public static void main(String args[]){  
     MultithreadingDemo obj=new MultithreadingDemo();   
     obj.start();  
  }  
}

Output:

My thread is in running state.

Example 2:

class Count extends Thread
{
   Count()
   {
     super("my extending thread");
     System.out.println("my thread created" + this);
     start();
   }
   public void run()
   {
     try
     {
        for (int i=0 ;i<10;i++)
        {
           System.out.println("Printing the count " + i);
           Thread.sleep(1000);
        }
     }
     catch(InterruptedException e)
     {
        System.out.println("my thread interrupted");
     }
     System.out.println("My thread run is over" );
   }
}
class ExtendingExample
{
   public static void main(String args[])
   {
      Count cnt = new Count();
      try
      {
         while(cnt.isAlive())
         {
           System.out.println("Main thread will be alive till the child thread is live");
           Thread.sleep(1500);
         }
      }
      catch(InterruptedException e)
      {
        System.out.println("Main thread interrupted");
      }
      System.out.println("Main thread's run is over" );
   }
}

Output:

my thread createdThread[my runnable thread,5,main]
Main thread will be alive till the child thread is live
Printing the count 0
Printing the count 1
Main thread will be alive till the child thread is live
Printing the count 2
Main thread will be alive till the child thread is live
Printing the count 3
Printing the count 4
Main thread will be alive till the child thread is live
Printing the count 5
Main thread will be alive till the child thread is live
Printing the count 6
Printing the count 7
Main thread will be alive till the child thread is live
Printing the count 8
Main thread will be alive till the child thread is live
Printing the count 9
mythread run is over
Main thread run is over

Method 2: Thread creation by implementing Runnable Interface

A Simple Example

class MultithreadingDemo implements Runnable{  
  public void run(){  
    System.out.println("My thread is in running state.");  
  }   
  public static void main(String args[]){  
     MultithreadingDemo obj=new MultithreadingDemo();  
     Thread tobj =new Thread(obj);  
     tobj.start();  
 }  
}

Output:

My thread is in running state.

Example Program 2:

Examine the program’s output and make an effort to comprehend what is going on. Understanding this example should be easy if you are familiar with how each thread technique is used.

class Count implements Runnable
{
   Thread mythread ;
   Count()
   { 
      mythread = new Thread(this, "my runnable thread");
      System.out.println("my thread created" + mythread);
      mythread.start();
   }
   public void run()
   {
      try
      {
        for (int i=0 ;i<10;i++)
        {
          System.out.println("Printing the count " + i);
          Thread.sleep(1000);
        }
     }
     catch(InterruptedException e)
     {
        System.out.println("my thread interrupted");
     }
     System.out.println("mythread run is over" );
   }
}
class RunnableExample
{
    public static void main(String args[])
    {
       Count cnt = new Count();
       try
       {
          while(cnt.mythread.isAlive())
          {
            System.out.println("Main thread will be alive till the child thread is live"); 
            Thread.sleep(1500);
          }
       }
       catch(InterruptedException e)
       {
          System.out.println("Main thread interrupted");
       }
       System.out.println("Main thread run is over" );
    }
}

Output:

my thread createdThread[my runnable thread,5,main]
Main thread will be alive till the child thread is live
Printing the count 0
Printing the count 1
Main thread will be alive till the child thread is live
Printing the count 2
Main thread will be alive till the child thread is live
Printing the count 3
Printing the count 4
Main thread will be alive till the child thread is live
Printing the count 5
Main thread will be alive till the child thread is live
Printing the count 6
Printing the count 7
Main thread will be alive till the child thread is live
Printing the count 8
Main thread will be alive till the child thread is live
Printing the count 9
mythread run is over
Main thread run is over

Thread priorities

  • The numbers known as thread priorities determine how one thread should be handled in relation to the others.
  • Context switching is the mechanism through which thread priority determines when to move from one executing thread to another.
  • The highest priority thread that is prepared to execute is given the CPU when a thread willingly relinquishes control.
  • No matter what a lower priority thread is performing, it is still possible for a higher priority thread to preempt it.
  • When a thread with a higher priority wants to execute, it does.
  • The setPriority() function, which belongs to the Thread Class class, is used to set the thread’s priority.
  • We may use MIN PRIORITY, NORM PRIORITY, or MAX PRIORITY in lieu of specifying the priority in integers.

Methods: isAlive() and join()

  • In all real-world scenarios, the main thread must complete last in order to prevent other threads that it has created from finishing first.
  • We may use the thread’s isAlive() function to check whether it has completed, which returns true otherwise.
  • Using the join() function, which lets the parent thread wait until the child thread has ended, is another approach to do this.
  • The Thread class has a definition for these methods.
  • In the samples above, we also utilized the isAlive() function.

Synchronization

  • Asynchronous behavior is introduced into programs through multithreading. Another thread may be reading the same data at the same time as one thread is producing it. This might result in inconsistencies.
  • There should be a mechanism in place to ensure that only one thread at a time may access a shared resource when two or more threads are required. This is accomplished via a process known as synchronization.
  • Java offers a synchronous method that may be used to create synchronous behavior. No other thread may invoke another synchronized method on the same object after it has entered a synchronized method. Then, each subsequent thread waits for the first thread to exit the synchronized block.
  • If the code for the method that has to be accessed synchronously is not accessible to us and we wish to synchronize access to objects of a class that was not intended for multithreaded access, we cannot add the synchronized to the necessary methods. The answer for this in Java is to enclose calls to the synchronization-required methods provided by this class within a synchronized block in the manner shown below.
Synchronized(object)
{
    // statement to be synchronized
}

Inter-thread Communication

There are just a few ways for Java threads to interact with one another. These are the wait(), notify(), and notifyAll methods (). Only a synchronized method may invoke any of these methods.
1) Java provides a monitor notion that may be used to understand synchronization. The monitor may be compared to a box that can only contain one thread. All other threads must wait until a thread quits the monitor after it has entered it.
2) Until another thread accesses the same monitor and uses notify, wait() instructs the caller thread to give up the monitor and go to sleep ().
3) The first thread to execute wait() on an object is woken up by notify().
All threads that invoked wait() on the same object are awakened by notifyAll(). First, the thread with the greatest priority will execute.

Related Articles

Leave a Reply

Your email address will not be published. Required fields are marked *

Back to top button