12 Threads in Java

12.1 INTRODUCTION

Running multiple programs/task on a computer is termed as multitasking. For example, running an MS-Word application and Visual C++ application at the same time is an example of multitasking. Each running instance of a program in memory is known as a process. Each process has a single unit of execution which is a thread. Thus, running multiple programs from user's point of view is multitasking, but from operating system's point of view, it is multithreading, which is also known as concurrent programming.

A process has a self-contained execution environment. A process generally has a complete, private set of basic run-time resources; in particular, each process has its own memory space. A multitasking operating system is capable of running more than one process (program) at a time by periodically switching the CPU from one task to another. A thread is a single sequential flow of control within a process. A single process can thus have multiple concurrently executing threads. Threads are sometime called lightweight processes. Both processes and threads provide an execution environment, but creating a new thread requires fewer resources than creating a new process.

Threads exist within a process-every process has at least one thread. Threads share the resources of the process, including memory and open files.

All the programs seen so far were single threaded programs. That is, they were having single flow of execution. A conventional process cannot continue performing its operations and at the same time return control to the rest of the program. In multithreading, there are several independent threads running concurrently in a program. Each thread provides a separate path of execution. From a logical point of view, multithreading means multiple lines of a single program can be executed at the same time; however, it is not the same as starting a program twice and saying that there are multiple lines of a program being executed at the same time. In this case, the operating system is treating the programs as two separate and distinct processes. In multithreading, CPU time given to a process is divided into all the threads the process is having.

Multithreading is a remarkable new feature in Java not supported by C/C++. Running program concurrently has a number of advantages. Multiple tasks can be divided into a number of tasks and can run parallel. This greatly enhances a system's capacity for concurrent execution of processes and threads. Threads enable you to create a more loosely coupled design revolving around a single thread. Many powerful applications related to graphics, animation, sound, etc. can be written efficiently using threads.

12.2 CREATING THREADS

In Java, there are two ways to create a thread.

1.   The first method is to inherit the class Thread and make it a base class for your class. Extending a class is the way Java inherits methods and variables from a parent class. In this case, one can only extend or inherit from a single parent class. The Thread class is defined in the package java. lang. The Thread class has a number of methods, a class can use, but the most important method is the run method which must be overridden to make the thread running. Thus, run() is the code that will be executed 'simultaneously' with the other threads in a program. Its simple syntax is as follows:

public void run()
{
   ..............
   ..............
}

2.   The second method is to implement Runnable interface, which is the frequently used method for implementing threads in the programs. The interface has just one method run which must be overridden. It can be used as follows:

class Mythread implements Runnable
{
    public void run()
    {
       ...........
       ...........
    }
}

Both the methods of creating threads are used.

12.2.1 Extending Thread Class

Creating a thread using this method simply involves creating a new class which extends the Thread class and overriding run method. To execute run method, start will be called, run() method to start the execution of thread. Consider the following program that creates two threads.

/* PROG 12.1 DEMO OF THREAD VER 1 */
class demo extends Thread
{
   public void run()
   {
          for (int i = 0; i < 5; i++)
                System.out.println(getName() + " i =  " + i);
   }
   demo()
   {
          start();
   }
}
class JPS1
{
   public static void main(String[] args)
   {
          demo d1 = new demo();
          demo d2 = new demo();
   }
}

OUTPUT:

Thread-0 i = 0
Thread-1 i = 0
Thread-0 i = 1
Thread-0 i = 2
Thread-0 i = 3
Thread-0 i = 4
Thread-1 i = 1
Thread-1 i = 2
Thread-1 i = 3
Thread-1 i = 4

Explanation: In the program, the class Thread is simply inherited into class demo, and demo, is made a thread class. In the default constructor of this class, the start method is called which in turn calls the run method. In the run method, a loop is run from 0 to 4. The getName method defined in the class Thread returns the name of the running thread. In the main, two threads d1 and d2 are created. Writing demo, d1 = new demo() calls the default constructor of the class demo, and through start method run is called. Same process applies for d2. Now, both threads run concurrently and execute code in their run method. Each time the program is run, one might get different output. For better understanding, the limit of for loop may be increased from 10 to, for example, 15 or 20.

/*PROG 12.2 DEMO OF THREAD VER 2 */
class demo extends Thread
{
   public void run()
   {
          try
          {
                for (int i = 0; i < 5; i++)
                {
                  System.out.println(getName()+"i="+i+" ");
                    Thread.sleep(1000);
                }
                System.out.println(getName()+" Fineshes");
          }
          catch (InterruptedException E)
          {
                System.out.println("Error: " + E);
          }
   }
}
class demo1 extends Thread
{
      public void run()
      {
          try
          {
                   for (int i = 0; i < 5; i++)
                   {
                     System.out.println(getName()+"i="+i+" ");
                     Thread.sleep(1000);
                   }
                   System.out.println(getName()+" Finishes");
          }
          catch (InterruptedException E)
          {
                   System.out.println("Error:" + E);
          }
      }
}
class demo2 extends Thread
{
   public void run()
   {
          try
          {
                   for (int i = 0; i < 5; i++)
                   {
                   System.out.println(getName()+"i="+i+"");
                     Thread.sleep(1000);
                   }
                   System.out.println(getName()+ " Finishes");
          }
          catch (InterruptedException E)
          {
                   System.out.println("Error:" + E);
          }
   }
}
class JPS2
{
   public static void main(String[] args)
   {
          demo d1 = new demo();
          demo d2 = new demo();
          demo d3 = new demo();
          d1.setName("Thread d1");
          d2.setName("Thread d2");
          d3.setName("Thread d3");
          d1.start();
          d2.start();
          d3.start();
   }
}

OUTPUT:

Thread d2 i = 0
Thread d3 i = 0
Thread d1 i = 0
Thread d3 i = 1
Thread d1 i = 1
Thread d2 i = 1
Thread d2 i = 2
Thread d1 i = 2
Thread d3 i = 2
Thread d2 i = 3
Thread d1 i = 3
Thread d3 i = 3
Thread d1 i = 4
Thread d3 i = 4
Thread d2 i = 4
Thread d1 Fineshes
Thread d2 Fineshes
Thread d3 Fineshes

Explanation: This time, three separate classes, demo1, demo2 and demo3, are created each of which extends the Thread class and overrides run method. In the main function, setName method of Thread class is made use of and names for the threads set. In the run method of each class, Thread.sleep method is made use of which takes a single parameter timeout of long type indicating time in millisecond. Thus, Threads d1, d2 and d3 sleep for 1000 milliseconds, 900 milliseconds and 800 milliseconds, respectively. Again for better understanding, increase the limit in the for loop from 5 to 10 or 15.

12.2.2 Thread Methods

The Thread class encapsulates a number of useful methods which can be used for controlling the way the thread behaves. Some of them are discussed below:

1.   public static Thread currentThread()

This method returns a reference to the currently executing thread object.

It can be used as follows:

class JPS
{
   public static void main(String args[])
   {
         Thread cur_thread = Thread.currentThread();
         System.out.println("Current Thread:= "+ cur_thread);
   }
}

The output will be: Current Thread:= Thread[main,5,main]

The output shows from left: the name of the thread, its priority and the group to which the thread belongs. The default name and priority is main and 5, respectively. The thread group is a collection of similar types of threads controlled by the runtime environment.

2.   public final String getName()
This method returns name of the thread as seen in earlier programs. The default name of the thread is Thread-0, Thread-1 and so on. The name of the thread can be changed using the setName method which assigns new name to the thread. Both getName and setName methods have been used earlier in the programs.

3.   public final int getPriority()
This method returns the priority of the thread. Thread priorities are discussed later in the chapter.

4.   public final boolean isAlive()
This method tests if this thread is alive. A thread is alive if it has been started and has not yet died. A true value indicates thread is alive and false means thread is dead.

5.   public final void join() throws InterruptedException
This method waits for the thread to terminate. Its usage will be shown later using program. The other overloaded form of the method is as follows:
public final void join(long millistime) throws InterruptedException
It waits for time (expressed in millisecond) to terminate. A 0 indicates wait forever.

6.   public static void yield()
This method causes the currently executing thread to temporarily pause and allow other threads to execute. Its usage will be shown later.

7.   public final void stop()
This method stops and kills a running thread. Currently, the thread does not stop unless it is running. If it is suspended, it does not die until it starts running again. The method is deprecated. For reasons, check out Java documentation.

The other methods suspend, resume, wait and notify, etc. are discussed later on in this chapter. Given below are few programs, which make use of some of the methods discussed above.

/*PROG 12.3 DEMO OF YIELD METHOD */
class JPS3 extends Thread
{
   private int count = 5;
   private static int TCount = 0;
   JPS3()
   {
          super(" " + ++TCount); ;
          start();
   }
   public void run()
   {
          while (true)
          {
            System.out.println("#" +getName()+" : "+count);
            if (--count == 0) return; //yield();
          }
   }
   public static void main(String[] args)
   {
          for (int i = 0; i < 3; i++)
                new JPS3();
   }
}

OUTPUT:

# 3 : 5
# 1 : 5
# 2 : 5
# 1 : 4
# 3 : 4
# 1 : 3
# 2 : 4
# 1 : 2
# 3 : 3
# 1 : 1
# 2 : 3
# 3 : 2
# 2 : 2
# 3 : 1
# 2 : 1

Explanation: In the program, three threads are created using new JPS3() and for loop. In the constructor, the super passes the name of the thread as String by concatenating it with TCount(). The run method of thread is called as start() is the next statement in the constructor. Each thread runs for its entirety and display, five values of count are displayed for thread 1 followed by thread 2 and thread 3. In the program, now remove the comment before yield. The new output is as shown below:

# 1 : 5
# 3 : 5
# 2 : 5
# 3 : 4
# 1 : 4
# 3 : 3
# 2 : 4
# 3 : 2
# 1 : 3
# 3 : 1
# 2 : 3
# 1 : 2
# 2 : 2
# 1 : 1
# 2 : 1

This is because after displaying one value of count, the first thread gives chance to second thread, which again on displaying one value of count gives chance to third thread which on displaying one value of count gives chances to first thread. Thus, all the three threads display one value of count in each turn just because of yield method. This is also known as round robin method in which each thread runs for a fixed amount of time and as the time is over gives chance to next waiting thread and sets at the back of the thread queue.

/*PROG 12.4 DEMO OF JOIN METHOD */
class JPS4 extends Thread
{
   JPS4(String str)
   {
          super(str);
          start();
   }
   public void run()
   {
          try
          {
          System.out.println("
Hello1 from thread"+
                                getName());
          Thread.sleep(500);
          System.out.println("
Hello2 from thread " +
                                getName());
          }
          catch (InterruptedException E)
          {
                System.out.println("Error:" + E);
          }
   }
   public static void main(String[] args)throws Exception
   {
          new JPS4("First").join();
          new JPS4("Second").join();
          new JPS4("Third").join();
   }
}

OUTPUT:

Hello1 from thread First
Hello2 from thread First
Hello1 from thread Second
Hello2 from thread Second
Hello1 from thread Third
Hello2 from thread Third

Explanation: The sleep method inside the run method causes enough delay so that another thread may get a chance to run, but due to join method each thread runs till it does not finish. That is why the output indicating full run of first thread is followed by second and third thread.

Without join method, the output will be as follows:

C:JPSch12>java JPS4
Hello1 from thread First
Hello1 from thread Second
Hello1 from thread Third
Hello2 from thread First
Hello2 from thread Second
Hello3 from thread Third
C:JPSch12>
/*PROG 12.5 DEMO OF ISALIVE METHOD */
class JPS5 extends Thread
{
   JPS5(String str)
   {
          super(str);
          start();
   }
   public void run()
   {
          try
          {
                System.out.println("Hello from thread "
                                    + getName());
                Thread.sleep(500);
                System.out.println("Bye from thread " +
                                    getName());
          }
                catch (InterruptedException E)
                {
                       System.out.println("Error:" + E);
                }
   }
   public static void main(String[] args)throws Exception
   {
          JPS5 d1 = new JPS5("First");
          JPS5 d2 = new JPS5("Second");
          JPS5 d3 = new JPS5("Third");
          System.out.println(d1.getName()+" Alive =
                              "+d1.isAlive());
          System.out.println(d2.getName()+" Alive =
                              "+d2.isAlive());
          System.out.println(d3.getName()+" Alive =
                              "+d3.isAlive());
          System.out.println("Main Thread is sleeping");
          System.out.println("for 1 seconds");
          Thread.sleep(3000);
          System.out.println(d1.getName()+" Alive =
                              "+d1.isAlive());
          System.out.println(d2.getName()+" Alive =
                              "+d2.isAlive());
          System.out.println(d3.getName()+" Alive =
                              "+d3.isAlive());
   }
}

OUTPUT:

First Alive = true
Hello from thread First
Hello from thread Third
Hello from thread Second
Second Alive = true
Third Alive = true
Main Thread is sleeping
for 1 seconds
Bye from thread First
Bye from thread Third
Bye from thread Second
First Alive = false
Second Alive = false
Third Alive = false

Explanation: As explained earlier in Section 12.22, the isAlive method returns true if thread on which it is called isalive. Initially, after starting all the three methods, calling isAlive method on all the threads result in true value from isAlive method. Then the main thread sleeps for 3 seconds. Next, when the isAlive method is called on the threads again, it returns false as the threads have done their execution and have terminated.

12.2.3 Implementing Thread Using Runnable

When thread methods are needed to be used, Runnable interface can be made use of for implementing threads in the programs. This is as shown in the program. For implementing threads using Runnable, an object of the class which implements the Runnable interface must be passed to Thread construct. This is shown as follows:

class demo implements Runnable
{
}

In main function, one will be writing like

Thread T = new Thread(new demo());

Or one can create an object of Thread class as member of the class implementing Runnable interface. The second approach is shown first.

/*PROG 12.6 THREAD IMPLEMENTATION USING RUNNABLE VER 1 */
class demo implements Runnable
{
   private int count = 5;
   Thread thr;
   demo(String s)
   {
          thr = new Thread(this, s);
          thr.start();
   }
   public void run()
   {
       while (true)
       {
             System.out.println("#"+thr.getName()+":"+count);
             if (--count == 0) return;
       }
   }
}
class JPS6
{
   public static void main(String[] args)
   {
          for (int i = 0; i < 3; i++)
               new demo("RUNNABLE THREAD " + (i + 1));
   }
}

OUTPUT:

#RUNNABLE THREAD 1:5
#RUNNABLE THREAD 3:5
#RUNNABLE THREAD 2:5
#RUNNABLE THREAD 3:4
#RUNNABLE THREAD 1:4
#RUNNABLE THREAD 3:3
#RUNNABLE THREAD 2:4
#RUNNABLE THREAD 3:2
#RUNNABLE THREAD 1:3
#RUNNABLE THREAD 3:1
#RUNNABLE THREAD 2:3
#RUNNABLE THREAD 1:2
#RUNNABLE THREAD 1:1
#RUNNABLE THREAD 2:2
#RUNNABLE THREAD 2:1

Explanation: For i=0 in main, String RUNNABLE THREAD 1 is passed to the demo constructor. The keyword this holds the reference of the current object. In the demo class, there is a reference of Thread class. The reference this and string s are passed as argument to the constructor of Thread class and thr starts referring the newly created object of Thread class. The next statement thr.start causes run method to be called. Same arguments apply to other two threads.

| /*PROG 12.7 THREAD IMPLEMENTATION USING RUNNABLE VER 2*/
class demo implements Runnable
{
   private int count = 5;
   public void run()
   {
          while (true)
          {
                 Thread t = Thread.currentThread();
                 System.out.println("#" + t.getName() + ":"
                                     + count);
                 if (--count == 0) return;
          }
   }

}
class JPS7
{
   public static void main(String[] args)
   {
          Thread T1 = new Thread(new demo(),"MyThread1");
          T1.start();
          Thread T2 = new Thread(new demo(),"MyThread2");
          T2.start();
   }
}

OUTPUT:

#MyThread1:5
#MyThread2:5
#MyThread1:4
#MyThread2:4
#MyThread1:3
#MyThread2:3
#MyThread1:2
#MyThread2:2
#MyThread1:1
#MyThread2:1

Explanation: In the program, a Thread reference is not made part of the demo class; instead the first approach has been used. In the main function, two objects of Thread class are created and in the constructor of Thread class reference of newly created demo object and thread name as string are passed.

12.3 THREAD PRIORITY

Priority for a thread can be set so that it runs before or after another thread. By default, all threads are created with normal priority. Priority makes a thread important. A higher priority thread runs first following which a lower priority thread will get a chance. In Java, Thread class provides three static fields for setting the priority of the threads:

1.   public static final int NORM_PRIORITY

2.   public static final int MIN_PRIORITY

3.   public static final int MAX_PRIORITY

The NORM_PRIORITY is the default priority all threads have. MIN_PRIORITY is the minimum priority a thread can have. Similarly, MAX_PRIORITY is the maximum priority a thread can have. The thread priority can be set using the setPriority method which takes an int value as argument. The getPriority method returns a thread's priority.

/*PROG 12.8 DEMO OF THREAD PRIORITY */
class demo implements Runnable
{
   private int count = 5;
   Thread thr;
   demo(String s, int p)
   {
          thr = new Thread(this, s);
          thr.setPriority(p);
          thr.start();
   }
   public void run()
   {
          while (true)
          {
                 System.out.println("#"+thr.getName()+":"+
                                            count);
                       if (--count == 0) return;
          }
   }
}
class JPS9
{
   public static void main(String[] args)
   {
          new demo("RUNNABLE THREAD ONE ",
                                     Thread.MIN_PRIORITY);
          new demo("RUNNABLE THREAD TWO ",
                                     Thread.MAX_PRIORITY);
          new demo("RUNNABLE THREAD THREE ",
                                     Thread.NORM_PRIORITY);
   }
}

OUTPUT:

#RUNNABLE THREAD TWO     :5
#RUNNABLE THREAD ONE     :5
#RUNNABLE THREAD THREE   :5
#RUNNABLE THREAD ONE     :4
#RUNNABLE THREAD TWO     :4
#RUNNABLE THREAD ONE     :3
#RUNNABLE THREAD THREE   :4
#RUNNABLE THREAD ONE     :2
#RUNNABLE THREAD TWO     :3
#RUNNABLE THREAD ONE     :1
#RUNNABLE THREAD THREE   :3
#RUNNABLE THREAD THREE   :2
#RUNNABLE THREAD THREE   :1
#RUNNABLE THREAD TWO     :2
#RUNNABLE THREAD TWO     :1

Explanation: In the program, the highest priority for thread TWO, minimum priority for thread ONE and normal priority for thread THREE are set. So thread TWO, THREE and ONE run in order.

12.4 THREAD SYNCHRONIZATION

A major concern when two or more threads share the same resource is that only one of them can access the resource at one time. Programmers address this concern by synchronizing threads.

Threads are synchronized in Java through the use of a monitor. Think of a monitor as an object that enables a thread to access a resource. Only one thread can use a monitor at any one time period. The thread owns the monitor for that period of time. The monitor is also called a semaphore.

A thread can own a monitor only if no other thread owns the monitor. If the monitor is available, a thread can own the monitor and have exclusive access to the resource associated with the monitor. If the monitor is not available, the thread is suspended until the monitor becomes available. Programmers say that the thread is waiting for the monitor.

Fortunately, the task of acquiring a monitor for a resource, happens behind the scenes in Java. Java handles all the details for the programmer. One has to synchronize the threads created in the program if more than one thread will use the same resource.

There are two ways in which threads can be synchronized: the synchronized method and the synchronized statement.

12.4.1 The Synchronized Method

All objects in Java have a monitor. A thread enters a monitor whenever a method modified by the keyword synchronized is called. The thread that is first to call the synchronized method is said to be inside the method and, therefore, owns the method and resources used by the method. Another thread that calls the synchronized method is suspended until the first thread relinquishes the synchronized method.

If a synchronized method is an instance method, it activates the lock associated with the instance that called this method, which is the object known as this during the execution of the body of the method. If the synchronized method is static, it activates the lock associated with the class object that defines the synchronized method.

Before learning how to define a synchronized method in a program, here is what might happen if synchronization is not used. This is illustrated by the following example. This program displays two names within parentheses using two threads. This-step process, where the opening parentheses using two threads. This is a three-step process, where the opening parenthesis, the name and the closing parenthesis are displayed in separate steps.

/*PROG 12.9 WITHOUT SYNCHRONIZATION */
class Parentheses
{
   void display(String s)
   {
          System.out.println("
");
          System.out.print("(" + s);
          try
          {
                Thread.sleep(1000);
          }
          catch (InterruptedException e)
          {
                System.out.println("Interrupted");
          }
          System.out.println(")");
   }
}
class MyThread extends Thread
{
   String s1;
   Parentheses p1;
   public MyThread(Parentheses p2, String s2)
   {
          p1 = p2;
          s1 = s2;
          start();
   }
   public void run()
   {
          p1.display(s1);
   }
}
class JPS10
{
   public static void main(String args[])
   {
          Parentheses p3 = new Parentheses();
          MyThread name1 = new MyThread(p3, "MPSTME");
          MyThread name2 = new MyThread(p3, "NMIMS");
          try
          {
                 name1.join();
                 name2.join();
          }
          catch (InterruptedException e)
          {
                 System.out.println("Interrupted");
          }
   }
}

OUTPUT:

(NMIMS(MPSTME)
)

Explanation: The program defines three classes: the Parentheses class, the MyThread class and the JPS10 class, which is the program class. The Parentheses class defines one method called display(), which receives a string in its argument list and displays the string in parentheses on the screen. The MyThread class defines a thread. In doing so, the constructor of MyThread requires two arguments. The first argument is a reference to an instance of the Parentheses class. The second argument is a string containing the name that will be displayed on the screen. The run() method uses the instance of the Parentheses class to call its display() method, passing the display() method the name that is to appear on the screen.

The rest of the action happens in the main() method of the JPS10 class. The first statement declares an instance of the Parentheses class. The next two classes create two threads. Notice that both threads use the same instance of the Parentheses class.

Here is what is displayed when this program is run. It is probably not what was expected. Each name should be enclosed within its own parentheses. The problem with the previous example is that two threads use the same resource concurrently. The resource is the display() method defined in the Parentheses class. In order to have one thread take control of the display() method, the display() method must be synchronized. This is done by using the keyword synchronized in the header of the display() method.

Now simply change the display method by writing synchronized keyword before void

synchronized void display(String s)
{
   ............
   ............
}

This time the output will be as follows:

(NMIMS)
(MPSTME)

12.4.2 The Synchronized Statement

Synchronizing a method is the best way to restrict the use of a method one thread at a time. However, there will be occasions when it will not be possible to synchronize a method, such as when encountering a class that is provided by a third party. In such cases, one does not have access to the definition of the class, which prevents one from using the synchronized keyword.

An alternative to using the synchronized keyword is the synchronized statement. A synchronized statement contains a synchronized block, within which is placed objects and methods that are to be synchronized. Calls to the methods contained in the synchronized block happen only after the thread enters the monitor of the object.

Although methods can be called within a synchronized block, the method declaration must be made outside a synchronized block.

The following example shows how to use a synchronized statement. This is basically the same as the previous example; however, the synchronized statement is used instead of the synchronized keyword. The synchronized statement is placed in the run() method within the MyThread class. The synchronized statement synchronizes the instance of the Parentheses class and thus prevents two threads from calling the display() method concurrently.

In the previous program, simply change the run method in MyThread class as follows:

public void run(){
   synchronized(p1)
   {
   p1.display(s1);
   }
}

Here, the display() method is not modified by synchronized. Instead, the synchronized statement is used inside the caller's run() method. This causes the same correct output as before, because each thread waits for the prior one to finish before proceeding.

12.5 THREAD COMMUNICATION

Usually all threads run at their own, independently from others, but sometimes threads have to coordinate their processing and, therefore, need to be able to communicate with each other during processing. Programmers call this interprocess communication.

One can have threads communicate with each other in a program by using the wait(), notify() and notifyAll() methods. These methods are called from within a synchronized method.

1.   The wait() method tells a thread to relinquish a monitor and go into suspension. There are two forms of the wait() method: One form does not require an argument and causes a thread to wait until it is notified; the other form of the wait() method allows to specify the amount of time to wait. The length of time in milliseconds is specified, which is passed to the wait() method.

2.   The notify() method tells a thread that is suspended by the wait() method to wake up again and regain control of the monitor.

3.   The notifyAll() method wakes up all the threads that are waiting for control of the monitor. Only the thread with the highest priority is given control over the monitor. The other threads wait in suspension until the monitor becomes available again.

All these methods are part of the object class within java.lang package

final void wait()throws InterruptedException
final void wait(long timeout) throws InterruptedException
final void notify()
final void noitfyAll()

The following program shows how to use these methods in an application. The objective of the program is to have the Producer class give a value to the Consumer class through the use of a Queue class. The Producer class places a value on the queues and then waits until the Consumer class retrieves the value before the Producer class places another value on the queue.

/*PROG 12.10 SOLUTION TO PRODUCER CONSUMER PROBLEM */
class Queue
{
   int Item;
   boolean busy = false;
   synchronized int get()
   {
          if (!busy)
                try
                {
                       wait();
                }
                catch (InterruptedException e)
                {
                       System.out.println("Get:
                                      InterruptedException");
                }
          System.out.println("Get: " + Item);
          notify();
          return Item;
   }
   synchronized void put(int Item)
   {
          if (busy)
                 try
                 {
                          wait();
                   }
                   catch (InterruptedException e)
                   {
                          System.out.println("Put:
                                         InterruptedException");
                   }
          this.Item = Item;
          busy = true;
          System.out.println("Put: " + Item);
          notify();
   }
}
class Producer extends Thread
{
   Queue q;
   Producer(Queue q)
   {
          this.q = q;
   }
   public void run()
   {
          for(int i=0;i<5;i++)
          {
                 q.put(i);
          }
   }
}
class Consumer extends Thread
{
   Queue q;
   Consumer(Queue q)
   {
          this.q = q;
   }
   public void run()
   {
          for(int i=0; i<5; i++)
          {
                 q.get();
          }
   }
}
class JPS11
{
   public static void main(String args[])
   {
          Queue q = new Queue();
          Producer P = new Producer(q);
          Consumer C= new Consumer(q);
          P.start();
             C.start();
   }
}

OUTPUT:

Put: 0
Get: 0
Put: 1
Get: 1
Put: 2
Get: 2
Put: 3
Get: 3
Get: 3
Put: 4

Explanation: The program defines four classes: the Queue class, the Producer class, the Consumer class and the JPS11 class. The Queue class defines two data members: Item and a flag. The Item is used to store the value placed on the queue by the Producer The flag variable is used as a sign indicating whether a value has been placed on the queue. This is set to false by default, which enables the producer to place a value on to the queue. The Queue class also defines a get() method and a put() method. The put() method is used to place a value on to the queue (that is to assign a value to the Item variables). The get() method is used to retrieve the value contained on the queue (i.e., to return the value of Item). Once the value is assigned, the put() method changes the value of the flag from false to true, indicating there is a value on the queue. Notice how the value of the flag is used within the get() method and the put() method to have the thread that calls the method wait until either there is a value on the queue or there is not a value on the queue, depending on which method is being called.

The Producer class declares an instance of the Queue class and then calls the put() method to place five integers on the queue. Although the put() method is called within for loop, each integer is placed on the queue and then there is a pause until the integer is retrieved by the Consumer class.

The Consumer class is very similar in design to the Producer class, except the Consumer class calls the get() method five times from within a for loop. Each call to the get() method is paused until the Producer class places an integer in the queue.

The main () method of the JPS11 class creates instances of the Queue class, the Producer class and the Consumer class. Notice that both constructors of the Producer class and the Consumer class are passed a reference to the instance of the same Queue class. They use the instance of the Queue class for inter-process communication.

Notice from the output that the value placed on the queue by the Producer is retrieved by the Consumer before the Producer places the next value on the queue.

12.6 SUSPENDED AND RESUMING THREADS

In programming with threads, the programmer may sometimes want to temporarily stop a thread processing and resume it later on. In such situations, one may use suspend and resume method provided by the Thread class. But these methods are deprecated. These are the methods used by Java 1.1 but are not supported by Java 2. The reason is that they are deadlock prone. Here, for the sake of how they were used in earlier Java programs, a small program is given which makes use of these methods. Later, a suspend and resume method will be written. The stop method for stopping a thread is also made use of. Once a thread is suspended, it can be resumed later on, but once a thread is stopped, it is dead and cannot be revived again.

/*PROG 12.11 DEMO OF SUSPEND, RESUME AND STOP METHOD */
class MyThread extends Thread
{
   String name;
   MyThread(String tname)
   {
          name = tname;
          start();
   }
   public void run()
   {
          try
          {
                for (int i = 0; i <= 10; i++)
                {
                      System.out.println(name + ": " + i);
                      Thread.sleep(100);
                }
          }
          catch (InterruptedException e)
          {
                System.out.println(name + " interrupted. ");
          }
          System.out.println(name + " exiting.");
   }
}
class sus_res
{
   public static void main(String args[])
   {
          MyThread T1 = new MyThread("First");
          try
          {
             Thread.sleep(500);
             T1.suspend();
             System.out.println("First threadsuspended");
             Thread.sleep(500);
             T1.resume();
             System.out.println("First thread resumed");
             Thread.sleep(300);
             System.out.println("First thread stopped");
             T1.stop();
          }
          catch (InterruptedException e)
          {
             System.out.println("Main Thread Interrupted");
          }
          System.out.println("Main thread exiting");
   }

}

OUTPUT:

First: 0
First: 1
First: 2
First: 3
First: 4
First thread suspended
First thread resumed
First: 5
First: 6
First: 7
First thread stopped
Main thread exiting

Explanation: The class MyThread extends Thread class and acts like a thread. The class has just one data member String class which stores the thread name. In the main, when an object of this class is created by the name T1, it is like creating a thread. The name of the thread is passed as string in the one argument constructor of String type.

/*PROG 12.12 WRITING OUR OWN SUSPEND AND RESUME METHOD */
class MyThread extends Thread{
   String name;
   boolean is_suspend;
   MyThread()
   {
          is_suspend = false;
          start();
   }
   public void run()
   {
          try
          {
                for (int i = 0; i < 10; i++)
                {
                      System.out.println("Thread: " + i);
                      Thread.sleep(200);
                      synchronized (this)
                      {
                            while (is_suspend)
                            {
                                   wait();
                            }
                      }
                 }
          }
          catch (InterruptedException e)
          {
                 System.out.println("Thread: interrupted");
          }
          System.out.println("Thread exiting ");
   }
   void mysuspend()
   {
          is_suspend = true;
   }
   synchronized void myresume()
   {
          is_suspend = false;
          notify();
   }
}
class JPS14_Demo{
   public static void main(String args[]){
          MyThread t1 = new MyThread();
          try
          {
                Thread.sleep(1000);
                t1.mysuspend();
                System.out.println("Thread: Suspended");
                Thread.sleep(1000);
                t1.myresume();
                System.out.println("Thread: Resume");
          }
          catch (InterruptedException e){
          }
          try
          {
                t1.join();
          }
          catch (InterruptedException e)
          {
          System.out.println("Main Thread: interrupted");
          }
   }
}

OUTPUT:

Thread: 0
Thread: 1
Thread: 2
Thread: 3
Thread: 4
Thread: Suspended
Thread: Resume
Thread: 5
Thread: 6
Thread: 7
Thread: 8
Thread: 9
Thread exiting

Explanation: The program defines a MyThread class. The MyThread class defines three methods: the run(), the mysuspend() and the myresume() method. In addition, the MyThread class declares the instance variable suspended, whose value is used to indicate whether or not the thread is suspended.

The run() method contains a for loop that displays the value of the counter variable. Each time the counter variable is displayed, the thread pauses briefly. It then enters a synchronized statement to determine whether the value of the suspended instance is true. If so, the wait() method is called, causing the thread to be suspended until the notify() method is called.

The mysuspend() method simply assigns true to the suspended instance variable. The myresume() method assigns false to the suspended instance variable and then calls the notify() method. This causes the thread that is suspended to resume processing.

The main method of the JPS14_Demo class declares an instance of MyThread and then pauses for about a second before calling the mysuspend() method and displaying an appropriate message on the screen. It then pauses for about another second before calling the myresume() method and again displays an appropriate message on the screen.

The thread continues to display the value of the counter variable until the thread is suspended. The thread continues to display the value of the counter once the thread resumes processing.

12.7 DAEMON THREADS

A daemon thread is one that is supposed to provide a general service in the background as long as the program is running, but is not part of the essence of the program. Thus, when all of the non-daemon threads complete, the program is terminated. Conversely, if there are any non-daemon threads still running, the program does not terminate.

In Java, for creating a daemon thread, setDaemon method of Thread class can be made use of. The signature of this is given as follows:

public final void setDaemon(boolean on);

Marks this thread as a daemon thread. The Java virtual machine exits when the only threads running are all daemon threads. This method must be called before the thread is started.

/*PROG 12.13 DEMO OF DAEMON THREAD */
class JPS15 extends Thread
{
   JPS15()
   {
          setDaemon(true); //must be called before start()
          start();
   }
   public void run()
   {
          while (true)
          {
                 try
                 {
                   System.out.println("
Daemon thread demo");
                   sleep(100);
                   }
                   catch (InterruptedException e)
                   {
                         System.out.println("Error");
                   }
          }
   }
   public static void main(String[] args)
   {
          new JPS15();
   }
}

OUTPUT:

Daemon thread demo

Explanation: In run(), the thread is put to sleep for a while. Once all the threads are started, the program terminates immediately, before any threads can print themselves, because there are no non-daemon threads (other than main()) holding the program open. Thus, the program terminates by printing the ' Daemon thread demo.

Whether a thread is a daemon, can be found out by calling isDaemon(). The signature of the method is given as follows:

public final boolean isDaemon()

The method tests if this thread is a daemon thread or not; if yes, then returns true.

If a thread is a daemon, any threads it creates, will automatically be daemons. See the program given below with a little modification from the above program.

/*PROG 12.14 DEMO OF ISDAEMON METHOD */
class JPS16 extends Thread
{
   Thread t;
   JPS16()
   {
          setDaemon(true); //Must be called before start()
                             start();
   }
   public void run()
   {
          while (true)
          {
          try
            {
                 t = new Thread("Daemon Thread");
          System.out.println("
IsDaemon = " + t.isDaemon());
          sleep(100);
            }
          catch (InterruptedException e)
          {
                System.out.println("Error");
          }
        }
   }
   public static void main(String[] args)
   {
          new JPS16();
   }
}

OUTPUT:

IsDaemon = true

Explanation: In the class, there is an object of Thread class as a member of JPS16 class. In the constructor of the JPS16 class, the setDaemon method marks this thread as daemon thread. Although the Thread object t was not a daemon thread yet isDaemon method on t returns true. This proves the point stated earlier.

12.8 PONDERABLE POINTS

1.   A thread is the smallest unit of execution.

2.   Execution of multiple tasks from a user's point of view is multitasking and from an operating system's point of view is multithreading.

3.   Each thread is a part of a process which is an instance of running program.

4.   A thread is sometimes known as light weight process.

5.   A thread can be created in Java either by extending Thread class or by implementing Runnable interface.

6.   All classes which either extend Thread class or implement Runnable interface have to implement run method which executes as a thread.

7.   The start method automatically calls the run method.

8.   In case, the method provided by the Thread class is not needed to be used, Runnable interface can be made use of for implementing a thread.

9.   The yield method of Thread class gives chance to other waiting threads.

10. The join method called on a thread waits till this thread finishes its execution.

11. The sleep method can be used for giving delay in execution.

12. Suspending a thread means suspending the processing temporarily. The suspended thread can be resumed later on by resuming it.

13. The stop method called on thread stops it from processing and makes it dead. A dead thread cannot be resumed.

14. For communication between threads, wait and notify method can be used.

15. For thread synchronization, synchronized keyword can be used; synchronized keyword can be applied on a method or on an object.

16. For synchronization, Java uses the built-in monitor construct. Only one thread at a time can be within the monitor at a time.

REVIEW QUESTIONS

1.   Explain the life cycle of the Thread.

2.   What are the methods described in Thread class?

3.   Explain the terms thread, multithreading, and multitasking?

4.   How is a Thread created? Explain in detail.

5.   Write short note on

(a) Thread group.

(b) Daemon thread

(c) Deadlock.

6.   What are the Thread priorities available in Thread class?

7.   Explain the characteristics of the thread.

8.   Write a program to implement Runnaable class to create a Thread.

9.   What is synchronization? Explain with suitable example.

10. How can you specify the delay time in your program?

11. What is the importance of thread synchronization in multithreading?

12. Is it necessary to synchronize single thread application?

13. Write a program to:

(a) Print the name, priority, and Thread group of the thread.

(b) Change the name of the current thread to "JAVA".

(c) Display the details of the current thread.

14. How do we start a thread?

15. What are the two methods by which we may stop threads?

16. What is the difference between suspending and stopping a thread?

17. What will be the output of the following program?

class test extedns Thread
{
   public void run()
   {
       System.out.println("sart");
       yield();
       resume();
       System.out.println("re-start");
       stop();
       resume();
       System.out.println("not start");
   }
   public static void main(String[]rk_and_sp)
   {
       test t = new test();
       t.start();
   }
}

Multiple Choice Questions

1.   A thread can be created in Java either by extending __________ or by implementing __________.

(a) thread class, runnable interface

(b) process, runnable interface

(c) suspend, resume

(d) none of the above

2.   All classes created in Java have to implement __________ which executes a thread

(a) suspend method

(b) notify

(c) run method

(d) is Alive method

3.   In case we do not want to use methods provided by the Thread class we can simply make use of __________ for implementing a thread.

(a) daemon thread

(b) thread priority

(c) runnable interface

(d) none of the above

4.   The __________ method automatically calls the __________method.

(a) suspend, start

(b) wait, isAlive

(c) wait, getName

(d) start, run

5.   Which method of Thread class gives chance to other waiting thread

(a) suspend

(b) resume

(c) yield

(d) run

6.   Which method is used for giving delay in execution

(a) wait

(b) suspend

(c) sleep

(d) notify

7.   Suspending the thread means suspending the

(a) giving delay in execution

(b) priority of the thread

(c) communication among the threads

(d) processing temporarily

8.   For making thread dead

(a) stop method is used

(b) suspend method is used

(c) dead method is used

(d) none of the above

9.   For communication between threads __________ can be used

(a) wait and run

(b) wait and notify

(c) wait and resume

(d) none of the above

10. A "daemon" thread is one that is supposed to provide a general service

(a) in communication

(b) in synchronization

(c) in the background

(d) none of the above

KEY FOR MULTIPLE CHOICE QUESTIONS

1.   a

2.   c

3.   c

4.   d

5.   c

6.   c

7.   d

8.   a

9.   b

10. c

..................Content has been hidden....................

You can't read the all page of ebook, please click here login for view all page.
Reset
18.190.239.166