CHAPTER 18

MULTI-THREADED PROGRAMMING

So far, we have written many programs. All of them can be termed as single threaded. For last many years, programming languages were producing single-threaded programs. Only recently, multi-threading support has appeared in programming languages. Java is providing an elegant, easy-to-use multi-threading environment to programmers.

Let us first understand what a thread is.

18.1 What are Threads?

When we start running a program, execution begins with method main. Executing of a method means executing statement after statement in sequence. Please note that loops like for and while are considered as a single (may be complex) statement. As CPUs started becoming faster and faster and OS started supporting multi-tasking, it becomes apparent that we should be able to run more than one method at a time. This brings in the concept of thread. One method (or group of some statements) is put in one envelope and sent for execution. At the same time, another code is sent for execution. The program controls them through some invisible monitoring mechanism. We imagine that these envelopes are tied to the programs by a thread.

Let us not bother how a single processor can execute two codes simultaneously. We will discuss it later.

18.2 Why Use Threads?

One of the main motives behind the introduction of threads is to maximize the use of resources. In simple terms, we want to run our programs faster. Consider a case in which we want to run a simple program of searching an array. It involves two tasks: reading data from file and specifying interactively the number N which we want to search.

Consider a pseudo code:

Read data from file;

Get N from console;

It is possible to run these actions in an overlapped manner, thereby saving time.

Let us take another example. Consider a case in which we want to compare bubble sort and quick sort. The methods for the same are available to us. We want both the methods to execute simultaneously. With our present programming knowledge, we can execute these methods one after the other. We cannot run them simultaneously.

This action is possible only when we do it with two threads. This excellent demonstration is available in The Java Tutorial. Readers are advised to see it to appreciate the power of threads. With so much motivation to study threads, let us start with creating and running threads.

18.3 Creating and Running a Thread

There are two ways to create a new thread of execution. One way is to declare a class to be a sub-class of Thread. This sub-class should override the run method of class Thread. The other way to create a thread is to declare a class that implements the Runnable interface. That class then implements the run method.

Let us start with the first method of creating thread. It will require the following steps.

Define a sub-class which extends class Thread.

The code we want to execute has to be placed in a method run() of this sub-class.

Next, create an object of this sub-class and execute the run method.

For example, a sub-class FirstThread could be written as follows:

class FirstThread extends Thread

  {  //  declarations

     //  constructor if required

      public void run ()

         {

           // The code we want to run comes here.

         }

  }

Next, the following code can be used to create the thread and set it running.

 FirstThread th1 = new FirstThread();

 th1.start();

As the concept of thread is quite complex, let us write a small program which runs only one thread. This will help us in getting familiar with a thread.

Problem: Write a program to demonstrate running of a single thread.

Solution: Since we have to run some useful code in a thread, let us take a simple example of sorting. We will sort a small array of integers in the thread (see Program 18.1).

 

PROGRAM 18.1 A Single Thread

 //     thr1.java

 class FirstThread extends Thread

      {   int A[] = {35,7,23,1,14};

    public static void sort(int [] A)

            {  int i,j,temp;

                 System.out.println("Initial data");

                 for(i=0; i<5;i++)

                     System.out.print(A[i]+" ");

                 System.out.println();

                 // now sorting

                 for(i=0; i<5-1;i++)

                    for(j=0; j<5-1;j++)

                    if( A[j]> A[j+1])

                       {  temp = A[j];

                          A[j] = A[j+1];

                          A[j+1] = temp;

                       }

               System.out.println("data after sorting");

               for(i=0; i<5;i++)

                   System.out.print(A[i]+" ");

            }

    public void run()

    {  sort(A);

    }

  }

 class thr1

  {  public static void main(String args[]  )

      { System.out.println("<---thr1.java--->");

        FirstThread th1 = new FirstThread();

        th1.start();

      }

  };

If we run the program, we will get the following output.

 

Output

 <---thr1.java--->

 Initial data

 35   7      23     1     14

 data after sorting

 1    7      14     23    35

You will ask me why is the running of a single thread shown in a chapter of multi-threading? Well, running many threads at a time is no different from running a single thread. And of course, if you cannot run even one thread, you cannot run many.

18.4 Creating Multiple Threads

After studying how a single thread comes into action, we are in a position to study what is called multi-threading, that is many threads in action (simultaneously). We have to start various threads one after the other by calling their start method.

Here, every thread is expected to run a specific code. By the word code, we mean a group of Java statements. We know that most of the time we have a single processor in a computer. Naturally, not all the threads are going to run simultaneously. The Java runtime machine switches execution of threads at short intervals. It gives us the illusion that all the threads are running simultaneously. Analogy can be drawn to a multi-tasking OS like Windows running various tasks simultaneously.

As every good thing has to come to an end, so does the thread. It is born, passes through different phases, and then comes to an end. This brings us to the life cycle of a thread.

18.5 Life Cycle of a Thread

A thread in its lifetime goes through various states. Let us study the life cycle of a thread in brief.

When we create a thread naturally, it is in “new” state. The most noticeable state is when the thread is running. We call it the “running” state. If there is any visible action (on screen), we can easily notice it. But as the time comes to run another thread, the current thread must go to another state.

In the next state, the thread is not running, but is ready to run when given a chance. This state is therefore called “runnable” state. (We may also call it “ready” state.)

Sometimes a thread requires some input data. It cannot proceed unless it is made available by the OS. Such a state is called a “blocked” state.

When a thread comes to the end of its code, naturally its life gets over. Hence, it enters a “dead” state.

Any thread starts with the new state and ends up in a dead state. During its life cycle, it moves from state to state. Figure 18.1 shows the state transition diagram of a thread’s life cycle.

Life Cycle of a Thread

Figure 18.1 Life Cycle of a Thread

We will describe these state transitions in the following table.

Path No Description
1 When we create a thread, it is normally in a position to run. Hence, it acquires ready state.
2 In a program, there may be many threads in the ready state. The JRE decides which one to start running. It selects a thread and starts executing it. Therefore, such a thread will move to the running state.
3 When the allocated (CPU) time of a thread is over, a running thread has to make way for another thread. Hence, JRE puts it back in the ready state.
4 Sometimes, a running thread may ask for disk input or may wait for some other event to occur. If such a thread keeps running, it will waste CPU time. Hence, JRE puts it in a state which can be described as the blocked state.
5 At a particular time, a running thread will come to its codes last statement (return). It implies that it is coming to its end. Naturally, it enters a state named “dead”.
6 & 7 Earlier it was possible to stop a thread by sending a stop command. In such a case, a thread which either is blocked or is in waiting state enters the dead state. Now since the method stop is deprecated, these paths are no more valid.
8 A thread in blocked state is actually waiting for something to happen. When that thing happens (say data available from disk), then the thread is capable of running again. Hence, it is put back in the ready state.

After studying the life cycle of a thread, now let us write a program with three threads. To make it interesting, let us use graphics.

Problem: Write a program which contains three threads.

Solution: See Program 18.2.

 

PROGRAM 18.2 Demo of Threads

 //       thgraph2.java

 import java.awt.*;

 class BPtimer

{ public static void delay(long n)

  { long t1,t2;

    t1 = System.currentTimeMillis();

    t1 = t1 + n;

    t2= System.currentTimeMillis();

    while (t2 < t1) t2= System.currentTimeMillis();

  }

}

 class VP extends Frame

 {   Graphics g1;

     VP (int xdim, int ydim)  //constructor

        { setSize(xdim,ydim);

        setBackground(Color.white);

        setVisible(true);

        g1=getGraphics();

        g1.setColor(Color.blue);

 }

 class A extends Thread

 { public void run()

 { for (int i = 0; i< 30;i++)

        { BPtimer.delay(150);

          g1.drawLine(100,100,100+i*10,100);

        }

          g1.drawString(" Exit from A",120,100-30);

 }

 }

 class B extends Thread

    { public void run()

      { for (int j = 0; j< 30;j++)

      { BPtimer.delay(150);

        g1.drawLine(100,200,100+j*10,200);

      }

        g1.drawString(" Exit from B",120,200-30);

      }

    }

 class C extends Thread

    { public void run()

      { for (int k = 0; k< 30;k++)

        { BPtimer.delay(110);

          g1.drawLine(100,300,100+k*10,300);

      }

      g1.drawString(" Exit from C",120,300-30);

     }

    }

 public void show_me()

    { new A().start();

      new B().start();

      new C().start();

    }

 }

 class thgraph2

    { public static void main(String args[])

      { VP vp1= new VP(500,400);

        vp1.show_me();

        // System.exit(0);

      }

 }

If you run this program, you will see all the three lines growing. The last line grows fastest. Thread C exits first. When all threads complete their execution, the following screen appears.

 

Output

ch18-ufig1

Note the last line marked in bold. It is removed by commenting out. If it is included, we do not see any output. Please note that it is not the last line but one line above that starts the running of the threads. They start running. At that time, if we close the program (actually Java runtime machine), everything gets closed.

18.6 Implementing Runnable Interface

As stated earlier, Java provides an alternate way to create a thread. We can declare a class that implements the Runnable interface. In this class, we have to implement the run method. To start a thread, first we have to pass the instance of this class as an argument.

 Class SecondThread implements Runnable

 {      //  declarations

        //  constructor if required

        public void run()

         {

            // The code we want to run comes here.

         }

   }

Now the following code can be used to create a thread and set it running.

 SecondThread th2 = new SecondThread();

 Thread some_name = new Thread(th2).start();

Please note the above carefully. th2 is the object of type SecondThread. We create a new Thread some_name with this object as a parameter. We call this method as the start for running this thread. This method invokes the run method of object th2. The above example can be reduced to the following code.

 SecondThread th2 = new SecondThread();

 new Thread(th2).start();

Let us study it with an example.

Problem: Write a program to demonstrate the use of interface Runnable.

Solution: Let us rewrite the earlier program (thr1.java) where we sort a small array of integers in the thread (see Program 18.3).

 

PROGRAM 18.3 Interface Runnable

 //     thr2.java

 //     Demonstrates interface Runnable

 class secondThread implements Runnable

   {  int A[] = {35,7,23,1,14} ;

       public void run()

         { sort(A);

         }

   public static void sort(int [] A)

       { int i,j,temp;

         System.out.println("Initial data");

         for(i=0; i<5;i++)

             System.out.print(A[i]+" ");

         System.out.println();

         //  now sorting

         for(i=0; i<5-1;i++)

             for(j=0; j<5-1;j++)

               if( A[j]> A[j+1])

                 {  temp = A[j];

                  A[j] = A[j+1];

                  A[j+1] = temp;

                 }

         System.out.println("data after sorting");

         for(i=0; i<5;i++)

             System.out.print(A[i]+" ");

       }

     }

 class thr2

     {  public static void main(String args[])

       {  System.out.println("<---thr2.java--->");

          System.out.println("Demonstrates interface Runnable");

          secondThread th2 = new secondThread();

          new Thread(th2).start();

       }

   };

If you run the program, you will see the following output.

 

Output

 <---thr2.java--->

 Demonstrates interface Runnable

 Initial data

 35   7      23     1     14

 data after sorting

 1    7      14     23    35

18.7 Thread Priority and Thread Scheduling Policy

It is possible to set a priority value to a thread. Java provides three predefined constants for this purpose, as shown in Table 18.1.

 

Table 18.1 Thread Priority Constants

Constant Meaning
MAX_PRIORITY The maximum priority that a thread can have.
MIN_PRIORITY The minimum priority that a thread can have.
NORM_PRIORITY The default priority that is assigned to a thread.

Please note that Java depends on thread scheduling policy of the OS, which is discussed further in the text for Windows XP. It uses the “preemptive thread scheduling” policy. When a higher priority thread becomes ready for execution, currently running lesser priority thread is stopped. A lower priority thread cannot preempt higher priority running thread. It has to wait until the running thread either completes or goes to blocking state for some reason.

If there are many threads with same priority, they are given an opportunity to run in round robin fashion.

Let us study a simple program to study this concept.

Problem: Write a program to demonstrate thread priority.

Solution: See Program 18.4.

 

PROGRAM 18.4 Thread Priority

 //     thread2.java

 //     thread priority

 class BPtimer

    {  public static void delay(long n)

       {  long t1,t2;

          t1 = System.currentTimeMillis();

          t1 = t1 + n;

          t2= System.currentTimeMillis();

          while (t2 < t1) t2= System.currentTimeMillis();

       }

    }

 class A extends Thread

    {  public void run()

       {  for  (int i = 1; i< 5;i++)

            {  BPtimer.delay(500);

               System.out.println(“== from thread A = ” + i);

            }

         System.out.println(“ Exit from A”);

       }

     }

 class B extends Thread

    {  public void run()

       {  for  (int j = 1; j< 5;j++)

            {  BPtimer.delay(500);

               System.out.println(“------ from thread B =” + j);

            }

         System.out.println(“ Exit from B”);

       }

     }

 class C extends Thread

    {  public void run()

        {  for (int k = 1; k< 5;k++)

             {  BPtimer.delay(500);

                System.out.println(“------ from thread C = “ + k);

             }

          System.out.println(“ Exit from C”);

       }

    }

 class thread2

    {  public static void main(String args[])

       {  System.out.println(“<---thread2.java--->”);

          A th1= new A();

            th1.setPriority(Thread.MIN_PRIORITY);

            th1.start();

          B th2 = new B();

            th2.setPriority(Thread.NORM_PRIORITY);

            th2.start();

          C th3 = new C();

            th3.setPriority(Thread.MAX_PRIORITY);

            th3.start();

       }

    }

If you run the program, you will see the following output.

 

Output

 <---thread2.java--->

 ********* from thread C = 1

 ********* from thread C = 2

 ********* from thread C = 3

 ********* from thread C = 4

     Exit from C

 ------ from thread B =1

 ------ from thread B =2

 ------ from thread B =3

 ------ from thread B =4

     Exit from B

 == from thread A = 1

 == from thread A = 2

 == from thread A = 3

 == from thread A = 4

     Exit from A

Let us modify our previous graphics program.

Problem: Write a program to demonstrate thread priority using graphics.

Solution: See Program 18.5.

 

PROGRAM 18.5 Threads Demo II

 //     th3.java

 import java.awt.* ;

 import javax.swing.* ;

 class BPtimer

    { public static void delay(long n)

      {  long t1,t2;

         t1 = System.currentTimeMillis();

         t1 = t1 + n;

         t2= System.currentTimeMillis();

         while (t2 < t1) t2= System.currentTimeMillis();

      }

    }

 class VP extends JFrame

    {  Graphics g1;

       VP (int xdim, int ydim) //constructor

          {  setSize(xdim,ydim);

             setBackground(Color.white);

              setVisible(true);

             g1=getGraphics();

             g1.setColor(Color.blue);

          }

    class A extends Thread

    {  public void run()

       {  for (int i = 0; i< 30;i++)

           {  BPtimer.delay(150);

              g1.drawLine(100,100,100+i*10,100);

           }

              g1.drawString(" Exit from A",120,100-30);

       }

    }

    class B extends Thread

      {  public void run()

         {  for (int j = 0; j< 30;j++)

              {  BPtimer.delay(250);

                 g1.drawLine(100,200,100+j*10,200);

              }

                 g1.drawString(" Exit from B",120,200-30);

         }

      }

    class C extends Thread

      { public void run()

         {  for (int k = 0; k< 30 ;k++)

           { BPtimer.delay(100);

             g1.drawLine(100,300,100+k*10,300);

           }

           g1.drawString(" Exit from C",120,300-30);

         }

      }

 public void show_me()

{  A th1 = new A();

      th1.setPriority(Thread.NORM_PRIORITY);

      th1.start();

      System.out.println(th1.toString());

      B th2 = new B();

      th2.setPriority(Thread.MAX_PRIORITY);

      th2.start();

      System.out.println(th2.toString());

      C th3 = new C();

      th3.setPriority(Thread.NORM_PRIORITY);

      th3.start();

      System.out.println(th3.toString());

    }

   }

 public class th3

{  public static void main(String args[])

     {  VP vp1= new VP(500,400);

        vp1.setDefaultCloseOperation(JFrame.EXIT_ON_CLOSE);

        // vp1.setVisible(true);

        BPtimer.delay(150); // note 1

        vp1.show_me();

        //System.exit(0);

     }

 }

If you run the program, at the end you will see the following output.

 

Output

ch18-ufig2

We have to watch this application while running. As Thread B is set to maximum priority, it runs and runs. It finishes before others could put even first step. Afterwards, both threads A and C start moving. As the priority of both C and A is the same, both run together.

There are many points to note in Program 18.5. Basically, code is repeated from thgraph2.java. However, delay in thread B is more that delay in A and delay in C. Still it starts as well as finishes even before others two could be visible. Delay in C is less than that of A. Hence, it runs faster than thread A. Lastly, we have added one more statement.

BPtimer.delay(150); // note 1

You may wonder why a delay is called at this place. Strictly speaking, this is not necessary. When we run the program without it, at times thread B started running even before the frame could become properly visible. When the frame becomes visible, whatever has been drawn before vanishes. This delay helps in getting proper output. Alternatively, we may add

vp1.setVisible(true);

to achieve the same result.

There are two types of threads in the system. The first one is called “Daemon thread”. The second type is normal or non-Daemon thread. In a program, many threads run. Eventually they die. Whenever all normal threads finish (terminate), the program comes to an end. The program does not wait for Daemon thread to terminate. Can we declare a thread as Daemon thread? Find the answer for yourself.

18.8 Synchronization

When we write multi-threaded programs, we may not imagine that there may be complications in the programs. Those of you who have studied the subject of “Operating System” are aware that there are problems like deadlocks. Without going into details, we may say that if two threads are using common data, there is a possibility of erroneous behaviour in the program. Let us take an example of standard producer–consumer problem.

A thread1 may be producing some data and thread2 may be using or consuming that data. If there is no proper synchronization between the two, there will be an arbitrary result.

Let us say that the producer is adding money in the basket and the consumer is picking it up. Both are acting with random time delay. If the producer adds to the basket when the consumer is picking it up, after a while the contents of the basket will be unpredictable. If we run the program for 1 hour, at the end the consumer may pick up more than what producer had produced.

To avoid this, we have to use what is known as synchronizing tools. Java provides many tools for synchronization. Let us study them one by one.

18.8.1 Synchronized methods

Let us again consider a producer–consumer problem. Both producer and consumer use object of class basket to put or get data. Let us assume we have method put_or_get(){…} in class basket. Let us define this method with keyword synchronised as follows:

    class basket

         { synchronised put_or_get()

                {

                // method body .

                }

         }

Now assume that both consumer and producer processes are running from different threads. If both of them want to use put_or_get() method simultaneously, the system will not allow them to do so. One of the threads has to wait until other thread finishes. This will solve any concurrency-related problem.

18.8.2 Synchronized statements

Synchronized statements offer another way to create synchronized code. A word synchronized placed before a block makes the block synchronized. Synchronized statements must specify the object that provides the intrinsic lock. Consider the following example. Here instead of a method, a statement (block) is synchronized.

    public void someName()

        { synchronized (this) {

            // statements

            }

In the previous paragraph, we talked of intrinsic lock. In Java, the whole process of Synchronization is based on the concept of intrinsic lock or monitor lock. We may simply call it as “monitor”.

Every object has an intrinsic lock associated with it. For proper working every thread must acquire this lock (monitor) before using object fields. The thread should release the monitor when it has finished its work. During this time, we can say that this thread owns the monitor and no other thread can acquire the same lock.

18.8.3 Methods wait(), notify(), and notifyAll()

We can use inter-thread communication for proper coordination among the threads. A thread may sleep until it is notified by the other thread. The “Object class” provides methods wait, notify, and notifyAll for this purpose.

Method wait() makes the thread to wait for getting the monitor. Since it is possible that this thread may be interrupted, it has to be used with try–catch block.

Method notify() wakes up a single thread that is waiting on this object’s monitor. Method notifyAll() wakes up all threads that are waiting on this object’s monitor.

It is important to note that all these methods must be called only when they own the monitor of that object. Otherwise, they throw IllegalMonitorStateException.

A thread becomes the owner of the object’s monitor by executing a synchronized instance method of that object. Alternately, it can do so by executing a synchronized statement which specifies that object.

18.8.4 Method join()

Java offers method join() in class Thread. It is quite useful in co-coordinating Threads. This method makes the current thread to wait until other specified thread terminates. Let us see this in action in the following program.

Problem: Write a program to demonstrate the use of method join().

Solution: Let us continue our example of drawing horizontal lines. Thread “A” draws the line undisturbed. In thread “B” we will draw only first 15 units. Then we will call join on thread “A”. This will suspend thread B until thread “A” ends. After that thread, “B” resumes and draws the remaining line.

 

PROGRAM 18.6 Demo of Method Join()

 //     th5.java

 import java.awt.* ;

 import javax.swing.*;

 class VP extends JFrame

   {   Graphics g1;

       VP (int xdim, int ydim) //constructor

          {  setSize(xdim,ydim);

             setBackground(Color.white);

             setVisible(true);

             g1=getGraphics();

             g1.setColor(Color.blue);

          }

 class A extends Thread

  {  public void run()

     {  for (int i = 0; i< 30;i++)

          {  try

                { sleep(250);}

             catch(Exception e){ };

             g1.drawLine(100,100,100+i*10,100);

           }

                g1.drawString(" Exit from A",120,100-30);

     }

  }

  static A th1;

  static B th2;

 class B extends Thread

  {  public void run()

      {

        for (int j = 0; j< 15;j++)

         { try

              {  sleep(200);}

            catch(Exception e){ };

           g1.drawLine(100,200,100+j*10,200);

         }

           g1.drawString(" waiting for A to finish",120,200-20);

         try

             {  th1.join() ;}

         catch(Exception e){ };

         g1.drawString(" Resuming operation",120,200+20);

         for (int j = 16; j< 30;j++)

             {  try

                  { sleep(250);}

                catch(Exception e){ };

                g1.drawLine(100,200,100+j*10,200);

             }

         g1.drawString(" Exit from B",120,200+40);

           }

         }

  //   static B th2;

 public void show_me()

  {  th1 = new A();

     th1.setPriority(Thread.NORM_PRIORITY);

     th1.start();

     th2 = new B();

     th2.setPriority(Thread.NORM_PRIORITY);

     th2.start();

  }

 }

 class th5

  {  public static void main(String args[])

      {  VP vp1= new VP(500,400);

         vp1.setTitle("Demo Of join() ");

         vp1.setDefaultCloseOperation(JFrame.EXIT_ON_CLOSE);

         vp1.setVisible(true);

         vp1.show_me();

     }

 }

When we run Program 18.6, we first see both threads A and B start drawing corresponding lines. Midway we see that thread B halts with the message “waiting for A to finish”. Thread A continues and finishes operation. Now thread B resumes with message “Resuming operation”. It continues until it completes its drawing task. It exits with the message “Exit from B”. The following figure shows the screenshot at the end of the program.

ch18-ufig3

Remember the famous tale of hare and tortoise? You may imagine thread A as tortoise. Thread B represents the hare which sleeps in between. It wakes up only when the tortoise wins the race.

Consider a case of reading an array from a file and sorting it. There is no way of sorting an array unless it is fully read. If the two actions of reading and sorting are in different threads, sorting can begin only when reading is complete, if we use the method join().

18.9 Timer and TimerTask

The package Java.util provides two important classes namely Timer and TimerTask. These are normally used in conjunction. Java offers the facility of running a thread in background. This thread schedules tasks for future execution. It can run thread once or repeatedly at regular intervals.

It goes without saying that tasks so scheduled should finish quickly. Also note that that there is no absolute guarantee that the task will be scheduled at specified time.

Let us study these classes with the help of an example.

Problem: Write a program to demonstrate Timer and TimerTask classes.

Solution: In this example, we will create a Timer object say timea. We want the program to run for say 5 seconds. We will put the main thread to sleep for 5,000 milliseconds. During this time, TimerTask will execute every 1000 milliseconds. In the timer Task, we will print word hello (see Program 18.7).

 

PROGRAM 18.7 TimerTask

 //   timer1.java

 import java.util.*;

 public class timer1

 {  public static void main(String args[])

     {  System.out.println("<---timer1.java--->");

        Timer timea = new Timer(true);

        timea.scheduleAtFixedRate(new MyTask(), 0, 1000);

        try

         {  Thread t = Thread.currentThread();

            t.sleep(5000);

         } catch (Exception e){};

   }

 }

 class MyTask extends TimerTask

    {

      public void run()

        {

         System.out.println("Hello");

        }

     }

If you run the above program, you will get the following output.

 

Output

   <---timer1.java--->

 Hello

 Hello

 Hello

 Hello

 Hello

 Hello

Please note that the word hello is printed six times. One expects it to print only five times. Change the sleep time by few milliseconds, less than 5,000 milliseconds, and you will get the word printed only five times.

You will ask me, why force main thread to sleep? The answer is that otherwise the program comes to an end immediately. The action we want to watch is guaranteed by the timer. We have to ensure that the program runs for a finite time.

Table 18.2 summarizes the constructors from class Timer.

 

Table 18.2 Constructor Summary: Class Timer

Timer() Creates a new timer.
Timer(boolean isDaemon) Creates a new timer whose associated thread may be specified to run as a daemon.
Timer(String name) Creates a new timer whose associated thread has the specified name.
Timer(String name, boolean isDaemon) Creates a new timer whose associated thread has the specified name and may be specified to run as a daemon.

Table 18.3 summarizes the methods from class Timer.

 

Table 18.3 Method Summary: Class Timer

void cancel() Terminates this timer, discarding any currently scheduled tasks.
int purge() Removes all cancelled tasks from this timer’s task queue.
void schedule(TimerTask task, Date time) Schedules the specified task for execution at the specified time.
void schedule(TimerTask task, Date firstTime, long period) Schedules the specified task for repeated fixed-delay execution, beginning at the specified time.
void schedule(TimerTask task, long delay) Schedules the specified task for execution after the specified delay.
void schedule(TimerTask task, long delay, long period) Schedules the specified task for repeated fixed-delay execution, beginning after the specified delay.
void scheduleAtFixed-Rate (TimerTask task, Date firstTime, long period) Schedules the specified task for repeated fixed-rate execution, beginning at the specified time.
void scheduleAtFixed-Rate (TimerTask task, long delay, long period) Schedules the specified task for repeated fixed-rate execution, beginning after the specified delay.

Table 18.4 summarizes the methods from class TimerTask.

 

Table 18.4 Methods Summary: Class TimerTask

boolean cancel() Cancels this timer task.
abstract void run() The action to be performed by this timer task.
long scheduledExecutionTime() Returns the scheduled execution time of the most recent actual execution of this task.

Table 18.5 summarizes the constructors from class Thread.

 

Table 18.5 Constructor Summary: Class Thread

Thread() Allocates a new Thread object.
Thread(Runnable target) Allocates a new Thread object.
Thread(Runnable target, String name) Allocates a new Thread object.
Thread(String name) Allocates a new Thread object.
Thread(ThreadGroup group, Runnable target Allocates a new Thread object.
Thread(ThreadGroup group, Runnable target, String name) Allocates a new Thread object so that it has target as its run object, has the specified name as its name, and belongs to the thread group referred to by group.
Thread(ThreadGroup group, Runnable target, String name, long stackSize) Allocates a new Thread object so that it has target as its run object, has the specified name as its name, belongs to the thread group referred to by group, and has the specified stack size.
Thread(ThreadGroup group, String name) Allocates a new Thread object.

Table 18.6 summarizes the methods from class Thread.

 

Table 18.6 Methods Summary: Class Thread

static int activeCount() Returns the current number of active threads in this thread’s thread group.
void checkAccess() Determines if the currently running thread has permission to modify this thread.
int countStackFrames() Deprecated. The definition of this call depends on suspend(), which is deprecated. Further, the results of this call were never well defined.
static Thread currentThread() Returns a reference to the currently executing thread object.
void destroy() Destroys this thread, without any clean-up.
static void dumpStack() Prints a stack trace of the current thread.
static int enumerate (Thread[] tarray) Copies into the specified array every active thread in this thread’s thread group and its sub-groups.
ClassLoader getContextClassLoader() Returns the context ClassLoader for this Thread.
String getName() Returns this thread’s name.
int getPriority() Returns this thread’s priority.
ThreadGroup getThreadGroup() Returns the thread group to which this thread belongs.
void interrupt() Interrupts this thread.
static boolean interrupted() Tests whether the current thread has been interrupted.
boolean isAlive() Tests if this thread is alive.
booleanisDaemon() Tests if this thread is a Daemon thread.
boolean isInterrupted() Tests whether this thread has been interrupted.
void join() Waits for this thread to die.
void join(long millis) Waits at most millis milliseconds for this thread to die.
voi djoin(long millis, int nanos) Waits at most millis milliseconds plus nanos nanoseconds for this thread to die.
void resume() Deprecated. This method exists solely for use with suspend(), which has been deprecated because it is deadlock-prone.
void run() If this thread was constructed using a separate Runnable run object, then that Runnable object’s run method is called; otherwise, this method does nothing and returns.
void setContextClassLoader (ClassLoadercl) Sets the context ClassLoader for this Thread.
voidsetDaemon (boolean on) Marks this thread as either a Daemon thread or a user thread.
voidsetName (String name) Changes the name of this thread to be equal to the argument name.
voidsetPriority(int newPriority) Changes the priority of this thread.
static voidsleep(long millis) Causes the currently executing thread to sleep (temporarily cease execution) for the specified number of milliseconds.
static voidsleep(long millis, int nanos) Causes the currently executing thread to sleep (cease execution) for the specified number of milliseconds plus the specified number of nanoseconds.
void start() Causes this thread to begin execution; the JVM calls the run method of this thread.
void stop() Deprecated. This method is inherently unsafe. Stopping a thread with Thread.stop causes it to unlock all of the monitors that it has locked (as a natural consequence of the unchecked ThreadDeath exception propagating up the stack).
void stop(Throwable obj) Deprecated. This method is inherently unsafe. See stop() (with no arguments) for details. An additional danger of this method is that it may be used to generate exceptions that the target thread is unprepared to handle (including checked exceptions that the thread could not possibly throw, were it not for this method).
void suspend() Deprecated. This method has been deprecated, as it is inherently deadlock-prone. If the target thread holds a lock on the monitor protecting a critical system resource when it is suspended, no thread can access this resource until the target thread is resumed. If the thread that would resume the target thread attempts to lock this monitor prior to calling resume, deadlock results. Such deadlocks typically manifest themselves as “frozen” processes.
String toString() Returns a string representation of this thread, including the thread’s name, priority, and thread group.
static void yield() Causes the currently executing thread object to temporarily pause and allow other threads to execute.

Keywords

blocked state, Daemon thread, dead state, getName(), getPriority(), interrupt(), isAlive(), isDaemon(), join(), MAX_PRIORITY, MIN_PRIORITY, NORM_PRIORITY, preemptive thread scheduling, ready state, run, Runnable, running state, start(), sleep(), synchronized, thread, thread life cycle, thread priority, Timer, TimerTask, yield()

RuleBook

NORM_PRIORITY NORM_PRIORITY is the default priority of a newly created thread.
Thread priority Threads may yield to threads of lower priority.
Thread simultaneous access It is possible for two threads to access the same variable or the same method of the same object at the same time. However, the net result will be unpredictable.
Thread class By using a thread class, multi-threaded program can be created.
Synchronized Every object that has synchronized methods has a monitor.
Monitor The sleep() method tells the calling thread to give up monitor until some other thread enters the same monitor.
Preemptive switching A thread priority is used to decide when to move from one running thread to the next. This is called preemptive switching.
sleep() The sleep() method is used to temporarily stop the execution of the thread.
join() The join() method suspends the current thread until that thread object dies.
start() After the start() method is called, the thread is in a Runnable state.

Review Questions

  1. What is a thread?
  2. What is the advantage of having threads?
  3. Which are the two different ways to create a thread?
  4. Describe various states of a thread.
  5. Draw the diagram for the life cycle of a thread and label the paths with appropriate methods for thread execution.
  6. Can we assign priority to a thread? If yes, how?
  7. What is the default priority?
  8. Explain inter-thread communication.
  9. Write a short note on Daemon threads.
  10. Write a short note on multi-threading.
  11. Write a short note on thread synchronization.

Exercises

  1. Write a program of threads in Java showing inter-leaving of actions from two threads: t1 and t2 synchronizing on a shared object.

    Let t1 print message ping--> and t2 print message <--pong. Take as command line arguments the following inputs to the program:

    Sleep Interval for thread t1

    Sleep Interval for thread t2

    Messages per cycle

    No. of cycles

  2. Write a small Java program to illustrate the use of Runnable interface.
..................Content has been hidden....................

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