Two Ways to Obtain a New Thread

image

There are two ways to obtain a new thread of control in Java. Either extend the Thread class, or write a class to implement the java.lang.Runnable interface and use it in the Thread constructor. The first way can be used only if your class doesn't already extend some other class (because Java disallows multiple parents).

  1. Extend class java.lang.Thread and override run():

    class Plum extends Thread {
         public void run() { /* more code */ }
    }

    Plum P = new Plum();
    P.start();

    or

  2. Implement the Runnable interface (the class Thread itself is an implementation of Runnable), and use that class in the Thread constructor:

    class Mango implements Runnable {
         public void run() { /* more code */ }
    }


    Mango m = new Mango();

    Thread t1 = new Thread( m );
    t1.start();

Figure 13-2 shows how a subclass of Thread is created by extending Thread.

Figure 13-2. Subclass of Thread created by extending Thread

image

Creating a thread looks confusing, because you have to start the thread running by calling a method that you did not write, namely start() in Figure 13-2. You extended or constructed Thread, so you will have Thread.start() by inheritance and all will be well.

Then, continuing to refer to Figure 13-2, declaring an object of class Plum gives you a new thread of control whose execution starts in the method run(). That isn't an OOP mechanism, it's just a name convention you have to know. Declaring two Plums (or more likely one Plum and one object of some other thread subclass) gives you two independently executing threads of control, and declaring and filling an array of Plums gives you an entire array.length of threads of control.

New threads do not start executing on creation. For some applications, programmers want to create threads (which incurs some system resource cost) in advance, then explicitly start them when needed (cheap), so this has been made the way it works. Create a thread like the following:

Mango m = new Mango();

You start it running by calling the start() method, like the following:

m.start();

Or you can create and start it in one step, like the following:

new Mango().start();

Execution then begins in the run() method, from where you can call other methods in this and other classes as usual. Remember: run() is the place where it starts, and start() gets it running. Another way to think of this is that run() is the equivalent of main() for a thread. You do not call it directly, but it is called on your behalf. If you ever see a call to run, like either of the following lines,

run()
something.run()

it means someone who didn't understand what they were doing wrote the code.

A few words on Runnable

The following is the alternative way to create your own threads. The Runnable interface looks like this:

public interface Runnable {
     public void run();
}

All it does is promise that an implementing class will have a no-arg method called run(). To turn a Runnable object into a Thread, you pass it as an argument to a Thread constructor, like this:

class Mango implements Runnable {
     public void run() { ... }
}
  /* more code */

Thread t1 = new Thread(new Mango());

Now you have a thread t1 that you can invoke all the Thread methods on, such as:

t1.start();
t1.stop();

You have to call start() to get t1 executing (just as if you had extended Thread). It's common to instantiate and start in one statement like the following:

new Thread (new Mango()).start();

However, you cannot have statements within the Runnable interface implementation of run() that invoke the Thread methods, like sleep() or getName() or setPriority().

This is because there is no Thread in our Runnable instance. So our Runnable doesn't know, and cannot directly invoke, any Thread-y things. This perhaps makes an implementation of Runnable slightly less convenient than a subclass of Thread. The code example coming up shows what won't work.

There is a simple workaround shown after the code example.

// Show the two ways to obtain a new thread
//   1.  extend class java.lang.Thread and override run()
//   2.  implement the Runnable interface,

class example {
   public static void main(String[] a) {

     // alternative 1
      ExtnOfThread t1 = new ExtnOfThread();
      t1.start();

     // alternative 2
      Thread t2 = new Thread (new ImplOfRunnable());
      t2.start();
   }
}

class ExtnOfThread extends Thread {
   public void run() {
         System.out.println("Extension of Thread running");
// next line compiles and runs just fine
         try {sleep(1000);}
         catch (InterruptedException ie) {return;}
   }
}

class ImplOfRunnable implements Runnable {
   public void run() {
         System.out.println("Implementation of Runnable running");

// next line will not compile - thread method sleep() not known
//         try {sleep(1000);}
//         catch (InterruptedException ie) {return;}
   }
}

The class Thread has many other methods shown later in the chapter. You can call these Thread methods only if you have a Thread object on which to invoke them. You don't get that automatically in a class that implements Runnable.

To get a Thread object, you call the static method Thread.currentThread(). Its return value is simply the currently running thread. Once you have that, you can easily apply any thread methods to it, as shown in the next example.

class ImplOfRunnable implements Runnable {
   public void run() {
         System.out.println("Implementation of Runnable running");
         Thread t = Thread.currentThread();
         try { t.sleep(1000); }
         catch  (InterruptedException ie) { return; }
   }
}

A call to currentThread() can appear in any Java code, including your main program. Once you have that thread object, you can invoke the thread methods on it.

The official word from the Java team is that you should use the Runnable interface if the run() method is the only one you are planning to override. The thinking is that, to maintain the purity of the model, classes should not be subclassed unless the programmer intends to modify or enhance the fundamental behavior of the class.

As with exceptions, you can provide a string argument when you create a thread subclass. If you want to do this, you must provide a constructor to take that string and pass it back to the constructor of the base class. The string becomes the name of the object of the Thread subclass and can later be used to identify it.

    class Grape extends Thread {
          Grape(String s){ super(s); } // constructor

          public void run() { /* code */ }
}
    /* more code */
     static public void main(String s[]) {
          new Grape("merlot").start();
          new Grape("pinot").start();
          new Grape("cabernet").start();

You cannot pass any parameters into the “run()” method because its signature would differ from the version it is overriding in Thread. A thread can, however, get the string with which it was started, by invoking the “getName()” method. This string could encode arguments or be an index into a static array of arguments as needed.

You have already seen enough to write an elementary Java program that uses threads. So do it. Write two classes that extend Thread. In one, the run() method should print “I like tea” in a loop, while the other prints “I like coffee”. Create a third class with a main() routine that instantiates and starts the other two threads. Compile and run your program.

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

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