Threads – Timed execution

This post continues the conversation on Java Threads (Thread in Java and Threads in Java – Termination being the previous two), to introduce the concept of timed execution. This refers to the process of running threads until a predetermined amount of time has elapsed. Using heuristics as an example, some authors choose to compared based on wall clock time instead of convergence or iteration bound.

 Timed thread execution example

The following example simply counts the number of iterations each thread performs (lines 84-87) over a predefined interval of time. The timer thread (lines 96-108) waits until the appropriate time has elapsed (lines 104-105), then interrupts all threads (line 106). As each computational thread runs until interruption (line 84), when the timer “goes off,” they gracefully shutdown (exit the while loop in this instance) and record the amount of “work” completed (line 88). An important note, the location of the timer start call relative to the computational threads will bias the results either for (if after) or against (if before). Here, the timer is called prior to the starting of the computational threads, thus there will be a slight negative bias. To minimize this affect, we have instantiated all computation threads (lines 27-28) prior to the timer call. This leaves only starting the threads (line 41) after the timer has begun, mitigating any negative affects instantiation might have on the process.

import static java.lang.System.out;
import java.util.ArrayList;
import java.util.List;
 
/**
 * This example illustrates one way to execute threads for a specified
 * duration of time. Here, we simply count the number of times an iteration
 * occurred during the allotted time.
 * @author Ray Hylock
 */
public class ThreadsTimer {
    // global variables
    private List<Thread> tList;
    private Thread timerThread;
    private long iterations;
    private static final long MAX_MS = 1000;    // 1 second
     
    /**
     * Creates, executes, and waits for threads to finish.
     * @param threads   the number of threads
     * @throws InterruptedException 
     */
    private void execute(final int threads) 
            throws InterruptedException{
        // create the threads
        tList = new ArrayList<Thread>();
        for(int i=0; i<threads; i++)
            tList.add(new Thread(new CompThread()));
         
        /*
         * Start the timer thread. Note: since this begins prior to the
         * start of the actual threads, the time will be slightly off
         * by a few milliseconds. Here, it is vital that CompThread
         * instantiation has occurred to minimize the time gap.
         */
        timerThread = new Thread(new TimerThread());
        timerThread.start();
        iterations = 0;
         
        // start threads
        for(Thread t : tList) t.start();    // calls run() in CompThread
         
        // wait for them to finish
        for(Thread t : tList) t.join();
         
        // print results
        out.println("Total iterations in " + MAX_MS + " ms: " + iterations);
    }
    /**
     * Adds to the number of iterations performed during the allotted time.
     * @param iterations the number of iterations completed during the 
     *                   allotted time
     */
    private synchronized void addIterations(final long iterations){
        this.iterations += iterations;
    }
     
    /**
     * Interrupts all threads. The threads will have to check the interrupted 
     * status {@link Thread#currentThread()#isInterrupted()} while iterating to
     * terminate gracefully.
     */
    private synchronized void stopThreads(){
        for(int i=0; i<tList.size(); i++)
            if(tList.get(i).isAlive()) tList.get(i).interrupt();
    }
     
    /**
     * The computational thread. Implements {@link Runnable}, so {@code run()} 
     * is executed when {@code start()} is invoked on an instantiated
     * {@link CompThread} object.
     */
    private class CompThread implements Runnable {
        /**
         * Create a new computational thread.
         */
        public CompThread (){}
         
        @Override
        public void run(){
            float x = 1.123456789f, y = 9.987654321f, z;
            long iterations = 0;
            // while uninterrupted
            while(!Thread.currentThread().isInterrupted()){
                z = x * y;      // 2 gets, 1 mult, 1 set
                iterations++;   // 1 get, 1 add, 1 set
            }
            addIterations(iterations);  // add to total
        }
    }
     
    /**
     * The timer thread. Once the desired number of milliseconds has elapsed 
     * the timer will terminate the process.
     */
    private class TimerThread implements Runnable {       
        /**
         * Create a new timer thread.
         */
        public TimerThread (){}
         
        @Override
        public void run(){
            double end = System.currentTimeMillis() + MAX_MS;
            while(System.currentTimeMillis() <= end){}
            stopThreads();
        }
    }
     
    /**
     * Main method.
     * @param args  command line arguments
     * @throws InterruptedException 
     */
    public static void main(String args[]) throws InterruptedException{
        int threads = 3;
        (new ThreadsTimer()).execute(threads);
    }
}

Output for the example class:

Total iterations in 1000 ms: 3521191146