Use Cases

Use Cases and Examples

Code strips: avoiding calls to wait()

As explained in the overview, Schedulables run more effectively as strips of code than as loops with a wait, since the blocking behavior of the wait will tie up a limited resource needlessly.

As an example, consider a thread-based queue pattern, which might look something the following.


class QueueRunner implements Runnable
{
    private SimpleQueue queue;
    private Thread thread;

    QueueRunner() {
	queue = new SimpleQueue(); // make the internal queue
	thread = new Thread(this, "My Queue");
	thread.start();  // start the thread
    }

    public void run() {
	Object next = null;
	while (true) {
	    while (true) {
		synchronized (queue) {
		    if (!queue.isEmpty()) {
			next = queue.pop();
			break; // process the next item
		    }
		    // queue is empty, wait to be notified of new items
		    try { queue.wait(); }
		    catch (InterruptedException ex) {}
		}
	    }
	    processNext(next);
	}
    }

    public void add(Object x) {
	synchronized (queue) {
	    queue.add(x);
	    queue.notify(); // wake up the wait()
	}
    }
}

This thread will spend most of its time in the wait call, which is not at all an effective use of a limited resource. As a Schedulable it would be better written as follows:


class QueueRunner implements Runnable
{
    private SimpleQueue queue;
    private Schedulable schedulable;

    QueueRunner() {
	queue = new SimpleQueue();
	// Create the Schedulable but don't start it yet.
	schedulable = threadService.getThread(this, this, "MyQueue");
    }

    public void run() {
	// Handle all items currently queued but never block
	Object next = null;
	while (true) {
	    synchronized (queue) {
		if (queue.isEmpty()) break; // done for now
		next = queue.pop();
	    }

	    processNext(next);
	}
    }

    void add(Object next) {
	synchronized (queue) {
	    queue.add(next);
	}
	// Restart the schedulable if it's not currently running.
	schedulable.start();
    }
}

Code strips: avoiding calls to sleep()

Another popular Java Thread pattern uses a sleep in a never-ending loop. As above, this uses up a thread resource even though the thread is rarely running.


class SleepingPoller implements Runnable 
{
    private int period;
    private String name;

    SleepingPoller(String name, Object client, int period) {
	this.name = name;
	this.period = period;
	ThreadService ts = (ThreadService)
	    sb.getService(this, ThreadService.class, null);
	ts.getThread(client, this, name).start();
        sb.releaseService(this, ThreadService.class, ts);
    }

    void initialize() {
	// Initialization code here
    }

    void executeBody()
	throws Exception
    {
	// Thread body here.
    }

    public void run() {
	initialize();
	while (true) {
	    try {
		executeBody();
	    }
	    catch (Exception ex) {
		log.error("Error in thread " + name, ex);
	    }
	    
	    try { Thread.sleep(period); }
	    catch { InterruptedExecption (ex) }
	}
    }
}

In this case the use of sleep can be replaced by having the run() method restart the thread after a delay.


class Poller implements Runnable 
{
    private Schedulable schedulable;
    private boolean initialized = false;
    private int period;
    private String name;
    private ThreadService ts;

    Poller(String name, Object client, int period) {
	this.name = name;
	this.period = period;
	this.ts = (ThreadService)
	    sb.getService(this, ThreadService.class, null);
	this.schedulable = ts.getThread(client, this, name);

	schedulable.start();
    }

    void ensureInitiolized() {
	synchronized (this) {
	    if (initialized) return;
	    initialized = true;
	}
	
	initialize();
    }

    void initialize() {
	// Initialization code here
    }

    void executeBody()
	throws Exception
    {
	// Thread body here.
    }

    public void run() {
	ensureInitiolized();
	try {
	    executeBody();
	}
	catch (Exception ex) {
	    log.error("Error in thread " + name, ex);
	}

        // Restart after period ms
	schedulable.schedule(period);
    }
}

Code strips: avoiding TimerTasks

TimerTasks are not controllable and should generally be avoided. Instead use the schedule methods on Schedulable for equivalent functionality. In this case the body of the task will run as a COUGAAR thread. Compare runTask() and runThreadPeriodically() below.


class MyPeriodicCode
{
    private int period;
    private Schedulable schedulable;

    public void body() {
	// The body of code to be run periodically goes here.
    }

    // In this version body() runs in the Thread Service's Timer
    // thread, which can be problematic if it takes too long.
    void runTask() {
	ThreadService ts = sb.getService(this, ThreadService.class, null);

	TimerTask task = new TimerTask() {
		public void run() {
		    body();
		}
	    };
	ts.schedule(task, 0, period);

	sb.releaseService(this, ThreadService.class, ts);
   }

    // In this version body() runs periodically as a cougaar thread.
    void runThreadPeriodically() {
	ThreadService ts = sb.getService(this, ThreadService.class, null);

	Runnable code = new Runnable () {
		public void run() {
		    body();
		}
	    };
	schedulable = ts.getThread(this, code, "MyPeriodicCode");

        // Restart the Schedulable every period ms
        schedulable.schedule(0, period);

	sb.releaseService(this, ThreadService.class, ts);
    }
}