Java Threads

Modified

Overview

Threads allow a program to perform multiple operations simultaneously and non-deterministically. A typical application needing multiple threads of execution is:

  1. one thread handles user input from mouse or keyboard
  2. a second thread is displaying a moving graphic such as a bouncing ball

The following is a quick look at Java threads.

Thread Example

The key point of Example1.java is the call of the start() method which:

  1. calls run() method
  2. returns immediately

The effect is the main thread starts one thread running, returns to the for-statement to start another.

 

// Example0.java

public class Example0 {
   public static void main(String args[]) throws Exception {
      for (int i=0; i<=4; i++) (new example( i )).run();
   }
}

class example {
   int N;

   example(int n) {
       this.N = n;
   }

   public void run() {
       System.out.println( "Start number: " + this.N );
       try { Thread.sleep( 10 ); }
       catch( Exception e ) {}
       System.out.println( "End number: " + this.N );
   }
}

// Example1.java

public class Example1 {
   public static void main(String args[]) throws Exception {
       for (int i=0; i<=4; i++) (new example( i )).start();
   }
}

class example extends Thread {
   int N;

   example(int n) {
      this.N = n;
   }

   public void run() {
      System.out.println( "Start number: " + this.N );
      try { Thread.sleep( 10 ); }
      catch( Exception e ) {}
      System.out.println( "End number: " + this.N );
   }
}

Start number: 0
End number: 0
Start number: 1
End number: 1
Start number: 2
End number: 2
Start number: 3
End number: 3
Start number: 4
End number: 4
Start number: 0
Start number: 1
Start number: 2
Start number: 3
Start number: 4
End number: 4
End number: 0
End number: 1
End number: 2
End number: 3

 

Serialization

In Example1.java  all threads execute with complete independence allowing for maximum parallelism. When multiple threads can operate on a common resource (e.g. printing to terminal output, changing a bank account balance), mutable access to the resource must be restricted to only a single thread at a time, called serialization.

Java provides an object monitor that when acquired prevents other threads from acquiring until released. The Example2.java has added a single, common object, common, accessible to 0..4 threads, that ensures the statements executed within the synchronized area are performed atomically (i.e. as one unit without other threads executing).

Note that the output of Example2.java is almost the same as sequential execution because the threads do nothing else in the run() method. Note that the main thread is not synchronized here so can execute on parallel with other threads.
 

// Example1.java

public class Example1 {
   public static void main(String args[]) throws Exception {
       for (int i=0; i<=4; i++) (new example( i )).start();
   }
}

class example extends Thread {

   int N;

   example(int n) {
      this.N = n;
   }

   public void run() {
      System.out.println( "Start number: " + this.N );
      try { Thread.sleep( 10 ); }
      catch( Exception e ) {}
      System.out.println( "End number: " + this.N );
   }
}

// Example2.java

public class Example2 {
   public static void main(String args[]) throws Exception {
      for (int i=0; i<=4; i++) (new example( i )).start();
   }
}

class example extends Thread {

   int N;
   static String common = "common object";

   example(int n) {
       this.N = n;
   }

   public void run() {
      synchronized( common ) {
         System.out.println( "Start number: " + this.N );
         try { Thread.sleep( 10 ); }
         catch( Exception e ) {}
         System.out.println( "End number: " + this.N );
      }
   }
}

Start number: 0
Start number: 1
Start number: 2
Start number: 3
Start number: 4
End number: 4
End number: 0
End number: 1
End number: 2
End number: 3
Start number: 0
End number: 0
Start number: 4
End number: 4
Start number: 3
End number: 3
Start number: 2
End number: 2
Start number: 1
End number: 1

 

Runnable interface

The Runnable interface allows extending and implementing, both a form of inheritance. Functionally, inheriting Thread or implementing Runnable produce identical results, the syntactical difference is minor as illustrated by the examples below.

// Example2.java

public class Example2 {
   public static void main(String args[]) throws Exception {
      for (int i=0; i<=4; i++) (new example( i )).start();
   }
}

class example extends Thread {

   int N;
   static String common = "common object";

   example(int n) {
       this.N = n;
   }

   public void run() {
      synchronized( common ) {
         System.out.println( "Start number: " + this.N );
         try { Thread.sleep( 10 ); }
         catch( Exception e ) {}
         System.out.println( "End number: " + this.N );
      }
   }
}

// Example3.java

public class Example3 {
   public static void main(String args[]) throws Exception {
      for (int i=0; i<=4; i++) new example( i ); 
   }
}

class example implements Runnable {

   int N; 
   static String common = "common object";

   example(int n) { 
       this.N = n;
       new Thread(this).start();
   }

   public void run() {
      synchronized( common ) {
         System.out.println( "Start number: " + this.N );
         try { Thread.sleep( 10 ); }
         catch( Exception e ) {}
         System.out.println( "End number: " + this.N );
      }
   }
}