Way2Java

Create Lightweight Heavyweight Threads

Create Lightweight Heavyweight Threads

Summary: In this tutorial "Create Lightweight Heavyweight Threads", you will create both lightweight and heavyweight threads in simple terms, programs and screenshots.

We know earlier, the meaning of heavyweight and lightweight threads in in Java Thread Basics with figures. Now, let us see how to create them.

1. Creating Heavyweight Threads

We know earlier, multithreading is nothing but executing multiple threads simultaneously. In the following program, two threads of different classes, Test1 and Test2 are created and executed. One thread prints the numbers in ascending order and the other in descending order, alternatively. As these threads belong to two different classes, it is an example of heavyweight process.

class Test1 extends Thread  
{
  public void run()   
  {
    for(int i=0; i<10;  i++)   
    {
      System.out.println("Test1: " + i);
      try  
      {
	Thread.sleep(1000);
      }
      catch(InterruptedException e)  
      { 
        e.printStackTrace();  
      }
    }    
  }   
}
class Test2 extends Thread   
{
  public void run()   
  {
    for(int i=9; i>=0; i--)   
    {
      System.out.println("Test2: " + i);
      try  
      {
        Thread.sleep(1000);
      }
      catch(InterruptedException e)  
      { 
        e.printStackTrace();  
      }
    }     
  }     
 }
 public class TwoRuns    
 {
   public static void main(String args[])  
   {
     Test1 t1  = new Test1();     
     Test2 t2  = new Test2();     
     t1.start();   
     t2.start();   
     try    
     {   
       t1.join();   
       t2.join();    
     }        				 
     catch( InterruptedException e )  
     { 
       e.printStackTrace(); 
     }
   }    
}               

The t1 prints 0 and becomes inactive for 1000 milliseconds by calling sleep() method. As the microprocessor does not have any work (or idle), it allocates its time to the waiting thread t2. t2 prints 9 and goes for sleep for 1000 milliseconds. Meantime, t1 comes out of sleep time, becomes active, prints 1 and again goes for sleep. Then t2 awakes, prints 8 and goes for sleep. Like this, the two loops managed by two threads (belonging to two different processes), t1 and t2, print the numbers alternatively. At any time given, only one thread is active and all the remaining are inactive. You can change the sleep timings and find the difference in output.

Observe, when t1 is active, t2 is inactive and when t2 is active, t1 is inactive. sleep() method is the easiest way, a programmer can shift the execution control from one thread to the other. Other methods also exist, but to activate an inactive thread, it requires an extra method call; this we get later.

Note : At different times of execution, you may see t2 starts first even though t1 is started first. It wholly depends on your processor speed and time availability.

t1.join();

One thread creates the other. The first thread, implicitly created and executed at the beginning of the process, is main thread. For us, main() is a method, but internally it is a thread. Do not get confused, there is a thread group on the name of main; this we get later. In the above program, main thread created t1 and t2 threads. main thread is known as parent thread and t1 and t2 are known as child threads. Here, the parent thread is main and it need not be the main, it can be another thread also. In multithreaded programming, the programmer should see that child thread dies first and then its creator, parent thread. If not, t1 and t2 become orphan threads and output may differ (again depends on the processor speed). Then, how to make the parent thread to die always later than the child. Call simply join() method on the child thread. join() method is an instruction to the JVM to see that parent thread should not be allowed to die before child dies, even if the parent thread completes its job early.

e.printStackTrace();

It is another style of printing the system defined exception message.

2. Creating Lightweight Threads

The above program is an example of heavyweight process. Let us modify the program to make it as a lightweight process. You know earlier, lightweight process means, shifting the execution control between the threads of the same process. That is here, two threads belong to the same class. It is just a modification of previous program.

public class TakeItLight extends Thread
{
  public void run()
  {
    String threadName = this.getName();
        
    if(threadName.equals("Ascending"))
    {
      for(int i=0 ; i <= 9; i++)
      {
        System.out.println(threadName + ": " + i);
        try
        {
          Thread.sleep(1000);
        }
        catch(InterruptedException e)
        {
          e.printStackTrace();
        }
      }
    }	
    else if(threadName.equals("Descending"))
    {
      for(int i=9; i >= 0; i--)
      {
        System.out.println(threadName + ": " + i);
        try
        {
          Thread.sleep(1000);
        }
        catch(InterruptedException e)
        {
          e.printStackTrace();
        }
      }
    }
  }          						// run() closure
  public static void main(String args[])
  {
    TakeItLight til1 = new TakeItLight();
    TakeItLight til2 = new TakeItLight();
           
    til1.setName("Ascending");
    til2.setName("Descending");

    til1.start();           
    til2.start();
    try
    {
      til1.join();
      til2.join();
    }
    catch(InterruptedException e)
    {
      e.printStackTrace();
    }
  }
}

til1.setName(“Ascending”);
til2.setName(“Descending”);

In this program, a small problem arises. Two threads til1 and til2 belong to the same class and executes the same run() method. Then, how to print ascending and descending order numbers alternatively. Here, we give the names to threads, retrieve the names in the run() method and act accordingly.

With setName() method of Thread class, a name to a thread can be assigned. The name given to til1 is Ascending and til2 is Descending.

String threadName = this.getName();

We know, this refers the current object. Here, the current thread is the one that calls the run() method; it is either til1 or til2. If til1 calls the run() method, this refers til1 and becomes internally as til1.getName(). It returns Ascending. Similarly, when til2 calls, the threadName variable becomes Descending. Using setName() and getName() methods of Thread class, we can assign and retrieve the names of threads. Remaining part of the code is explained in the previous program, TwoRuns.