Implementing Runnable
Home ] Up ] Creating a Thread ] Stopping a Thread ] Extending the Thread Class ] [ Implementing Runnable ] An Example ]

 

 

There are, however, situations where you want to have a class do thread work, but you also need that class to extend from another class. Since Java doesn't allow you to extend from more than a single class, you wouldn't be able to use the above technique. 

In this case, you'll need to use the Runnable interface instead. In general, you may prefer to use the Runnable technique, because it's more flexible.

Here's how you do the same thing as above, but using the Runnable interface:

package threads;

public class CountDownRunnable implements Runnable
{
  public CountDownRunnable(int countDown,
                           CountDownProgress progress)
  {
    m_countDown = countDown;
    m_progress = progress;
  }
  
  // The method that does the work of the thread
  public void run()
  {
    m_progress.started(getName() + 
                       ": started (counting from " +
                       m_countDown + ")");
    try
    {
      for (int i = m_countDown; i >= 0; i--)
      {
        Thread.sleep(1000);    // Sleep for 1 second
        // Audible 'tick'
        m_progress.tick(getName() + ": " + i);
      }
    }
    catch (InterruptedException e)
    {
      // Ignore
    }
    finally
    {
      m_progress.done(getName() + ": done!");
    }
  }
  
  /**
   * Gets the name of the thread this is running
   */
  private String getName()
  {
    return Thread.currentThread().getName();
  }
   
  /////// Private data ///////
  private int m_countDown;
  private CountDownProgress m_progress;
}

and here's the corresponding test program:

package threads;

import java.util.Random;

public class CountDownRunnableTester implements CountDownProgress
{
  /**
   *   Main entry point.
   *
   *   Arguments: list of thread names to use.
   */
  public static void main(String[] args)
  {
    Random random = new java.util.Random();
    CountDownRunnableTester tester = new CountDownRunnableTester();
    int threadCount = 5;
    for (int i = 1; i <= threadCount; i++)
    {
      // Generate a random number between 5 and 10
      int countDown = random.nextInt(5) + 5;
      CountDownRunnable runnable = 
          new CountDownRunnable(countDown, tester);
      Thread thread = new Thread(runnable, "Thread " + i);
      thread.start();
    }
  }
  
  public void started(String message)
  {
    System.err.println(message);
  }
  
  public void tick(String message)
  {
    System.err.println(message);
  }
  
  public void done(String message)
  {
    System.err.println(message);
  }
}

We still use the Thread class to cause a thread to start, but now we use it directly, specifying in the Thread constructor the class that implements the Runnable interface, to associate the runnable class with the thread.

The effect of using the Runnable interface is to separate the work (the code in the run() method) from the context in which it runs (the thread).

Here's what this program produced on my machine when I ran it (note that the actual output may vary because of the nature of multi-threading applications):

Thread 1: started (counting from 6)
Thread 2: started (counting from 7)
Thread 3: started (counting from 9)
Thread 4: started (counting from 6)
Thread 5: started (counting from 9)
Thread 1: 6
Thread 2: 7
Thread 3: 9
Thread 4: 6
Thread 5: 9
Thread 1: 5
Thread 2: 6
Thread 3: 8
Thread 4: 5
Thread 5: 8
Thread 2: 5
Thread 1: 4
Thread 5: 7
Thread 4: 4
Thread 3: 7
Thread 2: 4
Thread 1: 3
Thread 5: 6
Thread 3: 6
Thread 4: 3
Thread 2: 3
Thread 1: 2
Thread 5: 5
Thread 4: 2
Thread 3: 5
Thread 2: 2
Thread 1: 1
Thread 5: 4
Thread 3: 4
Thread 4: 1
Thread 2: 1
Thread 1: 0
Thread 1: done!
Thread 5: 3
Thread 4: 0
Thread 4: done!
Thread 3: 3
Thread 2: 0
Thread 2: done!
Thread 5: 2
Thread 3: 2
Thread 5: 1
Thread 3: 1
Thread 5: 0
Thread 5: done!
Thread 3: 0
Thread 3: done!

 

The page was last updated February 19, 2008