Java Tutorials - Herong's Tutorial Notes
Dr. Herong Yang, Version 6.00

CPU Execution Time Shared by Multiple Threads

This section provides a tutorial example on how to measuring CPU execution time allocated to threads with different setPriorities.

Question: If there are 5 application programs running on a single CPU system, and there 5 threads running in each of the 5 running application programs, how all the 25 threads get executed simultaneously on that one CPU?

The answer is that those 25 threads do not get executed simultaneous at any given instance of time. They get executed one at a time in turns to share the processing time of the single CPU. The following simple example illustrates how the processing time can be shared by multiple threads.

Assuming that:

  • The operating system is designed to execute the running application program one at a time in turns. For each turn, the selected application get executed for only 1 millisecond.
  • If an application program gets executed, it will execute the running threads one at a time in turns. For each turn, the selected thread gets executed for only 0.01 millisecond.
  • There are 5 threads running in each of the 5 running application programs.
  • The times spend on switch threads and application program in the CPU are ignorable.

If we let the system runs for 0.1 second, each application program will be executed 20 times for a total time of 20 milliseconds, and each thread will be executed 400 times for a total time of 4 milliseconds. So, for a fraction of a second (1/10 second), all threads in all applications programs will be executed for about 4 milliseconds. This will make you feel like all threads get executed simultaneously.

Now let's use the following program to see how each thread is getting its share of the CPU time:

/**
 * RacingThread.java
 * Copyright (c) 2002 by Dr. Herong Yang
 */
import java.util.*;
class RacingThread extends Thread {
   private static final long s_maxi = 1000000; // maximum number of steps
   private static final int t_maxi = 5; // maximum number of threads
   private static long[] t_done = new long[t_maxi];
   private static int t_last = -1; // index of the last thread
   private int t_indx; 
   private static int n_prime = 0;
   public static void main(String[] a) {
      System.out.println("Priority: (min, norm, max) = ("+
         Thread.MIN_PRIORITY+", "+
         Thread.NORM_PRIORITY+", "+
         Thread.MAX_PRIORITY+")");
      long start_time = new Date().getTime();
      for (int i=0; i<t_maxi; i++) {
         RacingThread t = new RacingThread();
         if (i==0) t.setPriority(Thread.MIN_PRIORITY);
         else if (i==1) t.setPriority(Thread.NORM_PRIORITY);
         else t.setPriority(Thread.MAX_PRIORITY);
         t.start();
      }
      System.out.print("Threads: ");
      for (int i=0; i<t_maxi; i++) {
         System.out.print(i+" ");
      }
      System.out.print("Time");
      while(true) {
         try {
            sleep(100);
         } catch (InterruptedException e) {
            System.out.println("Interrupted.");
         }
         System.out.print("\n  Steps: ");
         for (int i=0; i<t_maxi; i++) {
            System.out.print(t_done[i]+" ");
         }
         System.out.print((new Date()).getTime()-start_time);
      }
   }
   public RacingThread() {
      t_last++;
      t_indx = t_last;
      t_done[t_indx] = 0;
   }
   public void run() {
      for (long s=0; s<s_maxi; s++) {
      	 int n = 0;
      	 for (int i=3; i<100; i++) {// keep it busy for some time
      	    boolean is_prime = true;
      	    for (int j=2; j<i; j++) {
      	       is_prime = (i%j>0);
      	       if (!is_prime) break;
      	    }
      	    if (is_prime) n++;
      	 }
      	 n_prime = n;
         t_done[t_indx] = s;
      }
   }
}

Notes on the program design:

  • 5 sub-threads are created to do the same piece of work at each step. Steps are repeated for 1000000 times.
  • That same piece of work is to count how many prime numbers are there under 100.
  • The first sub-thread is given the lowest priority, the second sub-thread is given the medium priority, and the rest 3 sub-threads are given the highest priority.
  • Each sub-thread is recording the number of steps it has finished so far at the end of each step.
  • The main thread is repeatedly checking the recording array to see the execution progress of each sub-threads.
  • The elapse time in milliseconds is also reported each time the main thread is checking the recording array.
  • Each sub-thread is identified by an index number given in the constructor with the help of a static variable: t_last.
  • The static variable, n_prime, is updated by all 5 sub-threads repeatedly with the same value. I don't give any statement to print out the value of n_prime to verify the accuracy, but I did check the correctness of my prime number counting algorithm in a separate program.
  • The main thread will never end by itself. You need to press Ctrl-C to terminate the program.

See the next section for execution output of this program.

Sections in This Chapter

What Are Processes and Threads?

The "Thread" Class - Creating Thread Objects With Thread Sub Classes

The "Runnable" Interface - Creating Thread Objects with Runnable Objects

CPU Execution Time Shared by Multiple Threads

CPU Execution Time Shared by Multiple Threads - Test Output

Application Data Shared by Multiple Threads

Application Data Shared by Multiple Threads - Test Results

interrupt() - Method to Terminate Thread

Dr. Herong Yang, updated in 2008
CPU Execution Time Shared by Multiple Threads