Multithreading

<< Previous Chapter Next Chapter >>
Multithreading in Java:

Definition:
Multithreading is used to achieve multitasking in a java program. Java enables us to develop programs which have multiple sub programs (threads) which can run concurrently at the same time.
Few real examples of multi tasking like washing machine is able to wash and dry at the same time, we use gas stove which allows us parallel cooking at a same time, while browsing in internet we can open multiple pages at the same time, a media player plays the audio and show video in parallel.

In every program there is a situation which makes process idle for a time period.
Multiprocessing is a heavy weight multitasking whereas multithreading is a light weight multitasking. It means the threads are not a separate process; it is actually a sub program which runs under its parent process. There is no separate memory allocation for thread; it gets allocated inside its parent process memory area.
For example the spell checker and auto saving in msword runs in parallel, they are separate threads which belong to the msword process. If technology would have put them in separate process instead of putting in a thread it would have taken lots of switching time and memory. In multitasking the context switching is more than multithreading because in multitasking all processes are having separate memory area.

The set of instructions which are not occupying separate memory area, those instructions are forming a light weight process known as thread. So, the purpose is to achieve multithreading in java program. It also increase performance of our program, as idle time is very low and light weight processes runs concurrently. As we have discussed already about the garbage collection in java, the garbage collection is a separate thread in java which runs in parallel and look for the unreachable objects.

As we know everything in java is represented as an object, the thread is also represented as an object. Number of thread objects = number of threads.

Rule1 – one object is responsible to start only thread, if we will try to run more than one thread from a single object, it will throw exception.

Rule2 – creating object of thread class is must to create threads. This is a contract.



Fig. a high level thread process flow diagram.

We can never create main thread; we always create child threads only because main threads are created by JVM.

Lets run this small example to print current thread name,

package dev21century.threading;

public class Temp {
 public static void main(String[] args) {
  Thread thread = Thread.currentThread();
  System.out.println("Current Thread Name: " + thread.getName());
  System.out.println("Current Thread  Id: " + thread.getId());
 }
}

Output:

There are two standard ways to create threads in java, first way is extending Thread class and second way is by implementing Runnable interface. There is a third way using Executors which we will discuss in a separate chapter Java Concurrency Package.

Lets take this sample program of creating a thread using Thread class:

package dev21century.threading;

public class Thread1 extends Thread
{
  Thread1(String threadName)
  {
   super(threadName);
  }
      
  public void run()
  {
    for(int i = 0;i<5;i++)
     {
      System.out.println("Thread Name: " + getName());
     }
  }
      
  public static void main(String args[])
  {
    Thread1 thread1 = new Thread1("MyThread1");
    thread1.start();
  }
}

Output:


Rule1 – If we want to perform common type of tasks then create one thread and multiple objects.
Rule2 – whenever we want to perform a separate task on each thread then always keep separate thread class for each object.

Example:
Create a java file MainThread.java in dev21century.threading package:
package dev21century.threading;
//thread 1 class
class Thread1 extends Thread
{
      
       Thread1(String threadName)
       {
              super(threadName);
       }
       //run method is the main code of thread
       public void run()
       {
         for(int i = 0;i<5;i++)
          {
           System.out.println("Thread Name: " + getName());
          }
       }
}
//thread 2 class
class Thread2 extends Thread
{
       Thread2(String threadName)
       {
              super(threadName);
       }
      
       public void run()
       {
        for(int i = 0;i<10;i++)
         {
          System.out.println("Thread Name: " + getName());
         }
       }
}

//thread 3 class
class Thread3 extends Thread
{
       Thread3(String threadName)
       {
              super(threadName);
       }
      
       public void run()
       {
        for(int i = 0;i<20;i++)
         {
          System.out.println("Thread Name: " + getName());
         }
       }
}

public class MainThread {

       public static void main(String[] args) {

        Thread1 thread1 = new Thread1("MyThread1");
        Thread2 thread2 = new Thread2("MyThread2");
        Thread3 thread3 = new Thread3("MyThread3");
        thread1.start();
        thread2.start();
        thread3.start();
             
        for(int i = 0;i<20;i++)
        {
          System.out.println(Thread.currentThread().getName());
        }             
     }

}

Output:
Thread Name: MyThread2
Thread Name: MyThread3
main
Thread Name: MyThread1
Thread Name: MyThread2
Thread Name: MyThread3
main
Thread Name: MyThread1
Thread Name: MyThread2
Thread Name: MyThread3
main
Thread Name: MyThread1
Thread Name: MyThread2
Thread Name: MyThread3
main
Thread Name: MyThread1
Thread Name: MyThread2
Thread Name: MyThread3
main
Thread Name: MyThread1
Thread Name: MyThread2
Thread Name: MyThread3
main
Thread Name: MyThread2
Thread Name: MyThread3
main
Thread Name: MyThread3
Thread Name: MyThread2
main
Thread Name: MyThread3
Thread Name: MyThread2
main
Thread Name: MyThread2
Thread Name: MyThread3
main
Thread Name: MyThread3
main
Thread Name: MyThread3
main
Thread Name: MyThread3
main
Thread Name: MyThread3
main
Thread Name: MyThread3
main
Thread Name: MyThread3
main
Thread Name: MyThread3
main
Thread Name: MyThread3
main
Thread Name: MyThread3
main
Thread Name: MyThread3
main

The output may be different for you, as we are not sure JVM will run which thread first and how many contexts switching between them.

I have used Thread.sleep(milliseconds) here so that threads will keep waiting for 500 milliseconds and we can easily see the output.

Once object of thread class is created we have to call start() method of thread. The start() method internally call the run() method. The run() method is the only place where we can write the code of thread.
Note: we can also call the run method directly, in such case it will run as a normal method. This is one of the popular interview questions.

In above program if we omit the super() statement, then JVM will assign some default name like Thread -0, Thread-1 etc. if you want you can try this.

Second way of creating thread using Runnable interface – also called creating thread using association:

File Name: RunThread.java

package dev21century.threading;

class NewThread1 implements Runnable
{
 int x = 10;
 public void run() {
  for(int i = 1;i<10;i++)
   {
    System.out.println("Thread Name: " + Thread.currentThread().getName());
    try {
      Thread.sleep(500);
      } catch (InterruptedException e) {
         e.printStackTrace();
       }
    }
 }
}
public class RunThread {
  public static void main(String args[])
   {
    NewThread1 newThread1 = new NewThread1();
    Thread thread1 = new Thread(newThread1, "MyThread1");
    //passing thread object and thread name
    thread1.start();
             
    Thread thread2 = new Thread(newThread1, "MyThread2");
    //passing thread object and thread name
    thread2.start();
             
    }
}

Output:
Thread Name: MyThread1
Thread Name: MyThread2
Thread Name: MyThread1
Thread Name: MyThread2
Thread Name: MyThread1
Thread Name: MyThread2
Thread Name: MyThread1
Thread Name: MyThread2
Thread Name: MyThread1
Thread Name: MyThread2
Thread Name: MyThread1
Thread Name: MyThread2
Thread Name: MyThread1
Thread Name: MyThread2
Thread Name: MyThread2
Thread Name: MyThread1
Thread Name: MyThread2
Thread Name: MyThread1

Your output may be different.

In this example, inside Thread class constructor the first argument is of Runnable type, so we are passing our class object which has implemented the Runnable interface.

Here x is an instance variable, we have created only one object and passing twice so, variable x may be overridden. So, rule is if we have any instance variable in the class then it is recommended create that create separate objects and pass it to the thread class constructor.

Lets implements above in a simple program:
package dev21century.threading;

class NewThread2 implements Runnable
{
 int x;
 public void run()
  {
   for(int i =1;i<=5;i++)
    {
     System.out.println("Thread Name: " + Thread.currentThread().getName() + " " + this.x);
      
     try {
          Thread.sleep(500);
        } catch (InterruptedException e) {
            e.printStackTrace();
        }       
       }
      }
}
public class RunThread2 {
  public static void main(String[] args) {

   NewThread2 newThread2_1 = new NewThread2();
   newThread2_1.x = 50;
   Thread thread1 = new Thread(newThread2_1,"Thread1");
   thread1.start();
           
   NewThread2 newThread1_2 = new NewThread2();
   newThread1_2.x = 100;
   Thread thread2 = new Thread(newThread1_2, "Thread2");
   thread2.start();
           
   NewThread2 newThread1_3 = new NewThread2();
   newThread1_3.x = 150;
   Thread thread3 = new Thread(newThread1_3, "Thread3");
   thread3.start();

   for(int i = 1;i<5;i++)
    {
     System.out.println("Thread Name: " + Thread.currentThread().getName());
     try{
         Thread.sleep(500);
        }
     catch(Exception e)
      {
       System.out.println(e);
      }
     }
 }
}

Output:
Thread Name: main
Thread Name: Thread3 150
Thread Name: Thread1 50
Thread Name: Thread2 100
Thread Name: Thread3 150
Thread Name: Thread2 100
Thread Name: main
Thread Name: Thread1 50
Thread Name: Thread3 150
Thread Name: Thread2 100
Thread Name: main
Thread Name: Thread1 50
Thread Name: main
Thread Name: Thread1 50
Thread Name: Thread2 100
Thread Name: Thread3 150
Thread Name: Thread2 100
Thread Name: Thread3 150
Thread Name: Thread1 50

In above program we have maintained separate objects for all threads and instance variables obviously. The output may differ for you. Each threads has its own stack, so if thread completes then all its local variables will be destroyed.

Life Cycle of Thread:

Following steps describes the complete life cycle of a thread:
  1. Thread scheduler is a program which provides processor cycle to the threads and changes their state. This program is responsible for moving the threads from one state to the next whenever applicable. It does pooling in new state when thread comes in memory.
  2. As soon as a thread object is created and started, the scheduler marks the thread as a new and put that in runnable pool (stack), because it is not sure that the processor is free at the time when thread is arrived.
  3. Now, when processor becomes free, the scheduler picks the thread from runnable stack, mark it as running state and give it to the processor for processing.
  4. While running there is a chance for any interruption like wait for input, someone called sleep method, join method (will discuss later) etc. in such cases the scheduler marks the thread as waiting and move the thread to the blocked pool, and give chance to other waiting thread.
  5. Once the thread waiting on blocked state is resumed for some reason like input / output completed, sleep period completed, notify method invoked (will discuss later) etc. then the scheduler again pull the thread from blocking pool and move it to the runnable pool.
  6. Now, scheduler repeats these steps until thread is completed.


Fig. Life cycle diagram of Thread (Please click on Image to enlarge).

Thread Priority:
In java we have option to set priority for the threads, always the higher priority thread will be in running state. There is a method setPriority which is described in coming section.

Constructors:
Thread()
Thread(String s)
Thread(Runnable r)
Thread(Runnabel r, String s)
Thread(ThreadGroup rg, Runnable r)
Thread(ThreadGroup rg, Runnable r, String s)

Methods:
public void setName (String s)
public String getName ()
public void setPriority(int priority)
public int getPriority()
public void join(long milisecs)
public void join()
public void setDaemon(boolean b)
public boolean isDaemon()
public void interrupt()
public boolean isInterrupted()
public void suspend()                      //deprecated (removed from latest versions)
public void resume()                        //deprecated
public void stop()                              //deprecated

public static void Thread.currentThread()
public void yield()
public void start()
public boolean isAlive()


1) setPriority(int priority)

This method is used to set priority for a thread. It method accepts one of the following integer arguments:

Thread.MIN_PRIORITY)        1
Thread. NORM_PRIORITY) 5
Thread. MAX _PRIORITY)    10

If we pass value more than 10 then JVM will throw exception.

2) join()
Lets take a real example to understand the join concept, few persons having dinner on dining table and an another person join them, then the table manner says those people will wait until the newly joined person finish the dinner, even if they have completed eating.
Exactly same condition applies for thread as well; in java there is an option for a thread to join a running thread. In such case the already running thread will wait for the newly joined thread to finish, even if it has completed its task.

in jdk 1.0 & 1.1 it was a drawback that when the pare thread is dead and all its child threads will forcefully dead. But in later versions, no thread can be forcefully dead, that’s why all stop(), suspend() and resume() methods are deprecated.

Synchronization
Synchronization is one of the most important concept in multithreading, we have created a separate chapter where we will discuss synchronization and other concepts of multithreading. Please click on next chapter.


<< Previous Chapter Next Chapter >>





No comments:

Post a Comment