Saturday, January 11, 2020

Multi-threading

Multithreading in Java


Multi-Tasking


Multi-tasking allows users to perform multiple tasks at the same time. An operating system may provide a multitasking environment, where multiple processes can be executed simultaneously. In, multi-tasking each process requires its own separate address space. Context–switching is CPU intensive and needs a lot of time. Interprocess communication is expensive as this mechanism span to a separate address space. Processes are heavyweight.

What is Thread?


A thread is the smallest unit of code that can be dispatched by the thread scheduler. A single program can also perform multiple tasks by dispatching multiple threads for them. However, a single thread will be executed at a given point in time. A Thread is a lightweight process and a single process may contain several threads. For example, Multi-Player gaming for car racing games where car objects appearing on your screen may be a different Thread in itself. 

What is Multi-threading?


Multiple threads in a process share the same address space within the same process is known as multi-threading. Switching among multiple threads is less CPU intensive. Inter thread communication is less expensive as all threads share the same address space. Threads are lightweight processes and consume lesser operating system resources in comparison to a process. 

What are the problems with single Threaded Systems?


Single-threaded systems use an approach known as event looping or Polling. In this model, a single thread of control is used, which runs in an infinite loop. Polling is a single event queue which decides which instruction to execute next. Until this instruction is executed, nothing else can happen in the system This results in the wastage of precious CPU cycles.

Thread Lifecycle


The following diagram displays the life-cycle of a Thread.


Thread life-cycle
Thread life-cycle

A thread can be a not runnable state, because 
  • sleep() method invoked
  • suspend() method invoked
  • The thread calls wait() method to wait on a condition variable
  • I/O block

Creating Threads

There are two ways to create threads

  1. Extending Thread class
  2. Implementing Runnable Interface


Thread created by extending the “Thread” class


We can create Thread by extending the Thread(inheriting) class. This class must override the run() method. Code that should run as thread must be written inside the run() method.Start() method must be called to start this thread.However , in turn start() will call run() automatically.

Example

ttt//CREATING THE THREAD BY EXTENDING THREAD CLASS
public class MyThread extends Thread{
String tname;

public MyThread(String tname) {
      super();
      this.tname = tname;
}

@Override
public void run() {
      // we will give some work here to do
      for(int i=0;i<10;i++)
      {
            System.out.println("i am "+tname+" running "+i);
            // let's give here some pause
            try {
                  Thread.sleep(100);
            } catch (InterruptedException e) {
                  e.printStackTrace();
            }
      }    
}

public static void main(String[] args)
{
      MyThread red=new MyThread("RED");
      MyThread black=new MyThread("BLACK");
      MyThread green=new MyThread("GREEN");
      red.start();//Always call start() method to invoke 
      black.start();//the thread
      green.start();
     
}
}
Output:
i am RED running 0
i am BLACK running 0
i am GREEN running 0
i am RED running 1
i am BLACK running 1
i am GREEN running 1
i am RED running 2
i am BLACK running 2
i am GREEN running 2
i am RED running 3
i am BLACK running 3
i am GREEN running 3
i am RED running 4
i am BLACK running 4
i am GREEN running 4
i am RED running 5
......
.....
....So on
..


Creating Thread by “Runnable” Interface


Threads can also be created by Implementing Runnable Interface. Each class implementing the Runnable interface must implement the run() method.


Example

tt//CREATING THREAD BY IMPLEMENTING RUNNABLE INTERFACE
public class TestThread implements Runnable{
String tname;

public TestThread(String tname) {
      super();
      this.tname = tname;
}

@Override
public void run() {
      for(int i=0;i<100;i++)
      {
            System.out.println("i am "+tname+" running "+i);
            // let's give here some pause
            try {
                  Thread.sleep(100);
            } catch (InterruptedException e) {
                  e.printStackTrace();
            }
     
      }
}
public static void main(String[] args)
{
      Thread red=new Thread(new TestThread("RED"));
      Thread black=new Thread(new TestThread("BLACK"));
      Thread green=new Thread(new TestThread("GREEN"));
      red.start();//Always call start() method to invoke 
      black.start();//the thread
      green.start();
     
}
}

Output:
i am RED running 0
i am GREEN running 0
i am BLACK running 0
i am GREEN running 1
i am BLACK running 1
i am RED running 1
i am BLACK running 2
i am GREEN running 2
i am RED running 2
i am GREEN running 3
i am BLACK running 3
i am RED running 3
i am RED running 4
i am BLACK running 4
i am GREEN running 4
i am GREEN running 5
......
.....
....So on
..


Difference between extending Thread class and implementing Runnable interface

There is a significant difference between Threads created by extending thread class and implementing the Runnable interface. When we extend Thread class, we can’t extend any other class even we require and When we implement Runnable, we can save a space for our class to extend any other class in future or now.



Main Thread

The execution of the Java program starts with the main method. The main thread is created immediately as the main() method commences.

The main thread can be referred to as, 

Thread mymainthread=Thread.currentThread();

Thread Scheduler

Thread scheduler in java is the part of the JVM that decides which thread should run. There is no guarantee that which runnable thread will be chosen to run by the thread scheduler. Only one thread at a time can run in a single process. The thread scheduler mainly uses preemptive or time-slicing scheduling to schedule the threads. We can not start a thread more than once. If attempted so, it will throw IllegalThreadStateException.


What if we call the run() method directly instead of the start() method?

Each thread starts in a separate call stack. Invoking the run() method from the main thread, the run() method goes onto the current call stack rather than at the beginning of a new call stack.

The “join() method”


The join() method waits for a thread to die. In other words, it causes the currently running threads to stop executing until the thread it joins will complete its task. There are two overloaded versions of join() method.
  • public void join()throws InterruptedException
  • public void join(long milliseconds)throws InterruptedException


Thread Priority

Each thread has a priority. Priorities are represented by a number between 1 and 10. In most cases, the thread scheduler schedules the threads according to their priority (known as preemptive scheduling). But it is not guaranteed because it depends on JVM specification that which scheduling it chooses.
Three constants defined in Thread class:

  • public static int MIN_PRIORITY
  • public static int NORM_PRIORITY
  • public static int MAX_PRIORITY

Video tutorial