Available at http://java.sun.com/docs/books/tutorial/essential/concurrency/

Modified by Umar Kalim

Lab 3


Getting Started Using Threads

[Adapted from the Sun tutorial - Concurrency.]

This document shows you the steps to follow to create a multi threaded version of the classic Hello World program using Java Threads.

Defining and Starting a Thread

An application that creates an instance of Thread must provide the code that will run in that thread. There are two ways to do this:

Notice that both examples invoke Thread.start in order to start the new thread.

Pausing Execution with Sleep

Thread.sleep() causes the current thread to suspend execution for a specified period. This is an efficient means of making processor time available to the other threads of an application or other applications that might be running on a computer system. The sleep method can also be used for pacing, as shown in the example that follows, and waiting for another thread with duties that are understood to have time requirements, as with the SimpleThreads example in a later section.

The SleepMessages example uses sleep to print messages at two-second intervals:

public class SleepMessages {


    private String importantInfo[] = { 
              "Do you know who Habib Jalib is?",
              "Jalib was a renowned Pakistani Urdu poet.",
              "Born in 1928; died March 12, 1993.",
              "Details are available at http://en.wikipedia.org/wiki/Habib_Jalib"
          };


        public static void main(String args[]) {
          (new SleepMessages()).start();
        }

        public void run() {
            for (int i = 0; i < importantInfo.length; i++) {
              try{
                //Pause for 2 seconds
                Thread.sleep(2000);
              }
              catch (InterruptedException e){
                e.printStackTrace();
              }
              //Print a message
              System.out.println(importantInfo[i]);
            }
        }
 }    

Notice that there is a try-catch block for InterruptedException. This is an exception that sleep throws when another thread interrupts the current thread while sleep is active.

The Counters

Here is an example where implement a counter and instantiate three threads which race against each other.

public class Counter extends Thread{

public int count = 1;

public void run() {
while (count < 50) {
try {
sleep(500);
threadMessage("count - " + count);
} catch (InterruptedException e) { }
count++;
}
}

public static void main(String arg[]){
Counter c1 = new Counter();
Counter c2 = new Counter();
Counter c3 = new Counter();
c1.start();
c2.start();
c3.start();
}

//Display a message, preceded by the name of the current thread
static void threadMessage(String message) {
String threadName = Thread.currentThread().getName();
System.out.format("%s: %s%n", threadName, message);
}
}

 

Interrupts

An interrupt is an indication to a thread that it should stop what it is doing and do something else. It's up to the programmer to decide exactly how a thread responds to an interrupt, but it is very common for the thread to terminate.

A thread sends an interrupt by invoking interrupt on the Thread object for the thread to be interrupted. For the interrupt mechanism to work correctly, the interrupted thread must support its own interruption.

Supporting Interruption

How does a thread support its own interruption? This depends on what it's currently doing. If the thread is frequently invoking methods that throw InterruptedException, it simply returns from the run method after it catches that exception. For example, consider the central message loop in the SleepMessages example which is in the run method of a thread's Runnable object. It supports interrupts since it has the try-catch block for InterruptedException.

The interrupt mechanism is implemented using an internal flag known as the interrupt status. Invoking Thread.interrupt sets this flag. When a thread checks for an interrupt by invoking the static method Thread.interrupted, interrupt status is cleared. The non-static Thread.isInterrupted, which is used by one thread to query the interrupt status of another, does not change the interrupt status flag.

By convention, any method that exits by throwing an InterruptedException clears interrupt status when it does so. However, it's always possible that interrupt status will immediately be set again, by another thread invoking interrupt.

One can also use Thread.interrupted to check whether the interrupt flag has been set or not?

Joins

The join method allows one thread to wait for the completion of another. If t is a Thread object whose thread is currently executing,

t.join(); 
causes the current thread to pause execution until t's thread terminates. Overloads of join allow the programmer to specify a waiting period. However, as with sleep, join is dependent on the OS for timing, so you should not assume that join will wait exactly as long as you specify.

Like sleep, join responds to an interrupt by exiting with an InterruptedException.

Simple Threads

Lets put all this together...

SimpleThreads consists of two threads. The first is the main thread that every Java application has. The main thread creates a new thread from the Runnable object, MessageLoop, and waits for it to finish. If the MessageLoop thread takes too long to finish, the main thread interrupts it.

The MessageLoop thread prints out a series of messages. If interrupted before it has printed all its messages, the MessageLoop thread prints a message and exits.

public class SimpleThreads {


        //Display a message, preceded by the name of the current thread
        static void threadMessage(String message) {
          String threadName = Thread.currentThread().getName();
          System.out.format("%s: %s%n", threadName, message);
        }

        private static class MessageLoop implements Runnable {
          public void run() {
            String importantInfo[] = {
              "Do you know who Habib Jalib is?",
              "Jalib was a renowned Pakistani Urdu poet.",
              "Born in 1928; died March 12, 1993.",
              "Details are available at http://en.wikipedia.org/wiki/Habib_Jalib"
            };
    
            try {
                for (int i = 0; i < importantInfo.length; i++) {
                    //Pause for 3 seconds
                    Thread.sleep(3000);
                    //Print a message
                    threadMessage(importantInfo[i]);
                }

            } catch (InterruptedException e) {
                  threadMessage("I wasn't done!");
            }
          }
        }

        public static void main(String args[]) throws InterruptedException {
          //Delay, in milliseconds before we interrupt MessageLoop
          //thread (default one hour).
          long patience = 1000 * 60 * 60;

          //If command line argument present, gives patience in seconds.
          if (args.length > 0) {
              try {
                  patience = Long.parseLong(args[0]) * 1000;
              } catch (NumberFormatException e) {
                  System.err.println("Argument must be an integer.");
                  System.exit(1);
              }
          }

          threadMessage("Starting MessageLoop thread");
          long startTime = System.currentTimeMillis(); 
          Thread t = new Thread(new MessageLoop());
          t.start();

          threadMessage("Waiting for MessageLoop thread to finish");
          //loop until MessageLoop thread exits

          while (t.isAlive()) {
              threadMessage("Still waiting...");
              //Wait maximum of 1 second for MessageLoop thread to
              //finish.
              t.join(1000);
              if (((System.currentTimeMillis() - startTime) > patience) &&
                      t.isAlive()) {
                  threadMessage("Tired of waiting!");
                  t.interrupt();
                  //Shouldn't be long now -- wait indefinitely
                  t.join();
              }
           }
          threadMessage("Finally!");
      }
  } 

Last updated - 14/Nov/2007