// **********************************************************************
//
// <copyright>
//
// BBN Technologies
// 10 Moulton Street
// Cambridge, MA 02138
// (617) 873-8000
//
// Copyright (C) BBNT Solutions LLC. All rights reserved.
//
// </copyright>
// **********************************************************************
//
// $Source: /cvs/distapps/openmap/src/openmap/com/bbn/openmap/layer/vpf/RunQueue.java,v $
// $RCSfile: RunQueue.java,v $
// $Revision: 1.3 $
// $Date: 2004/10/14 18:06:09 $
// $Author: dietrick $
//
// **********************************************************************
package com.bbn.openmap.layer.vpf;
import java.util.ArrayList;
import java.util.List;
/**
* Implement a very basic thread scheduling mechanism.
*
* TerminatingRunnable objects get added to the queue. As the thread
* gets cpu time, it will sequentially dequeue and run the objects in
* the queue in a LIFO order. Duplicates are allowed in the queue. Run
* will get called exactly once for each enqueue call. Only one thread
* will run at a time. (The next object won't run until the previous
* one completes.)
*
* @see java.lang.Runnable#run()
*/
public class RunQueue extends java.lang.Thread {
/** the queue of objects to run */
final private List<Runnable> queue = new ArrayList<Runnable>(); //fixed, unique
/** used to give threads unique names */
static private int tcount = 0;
/**
* default constructor. priority and daemon status inherited from
* the calling thread. This thread is NOT started
*/
public RunQueue() {
this(null); //call constructor with ThreadGroup arg
}
/**
* construct this thread in a particular ThreadGroup
*
* @param tg the ThreadGroup to be in. <code>null</code> means
* the current ThreadGroup
*/
public RunQueue(ThreadGroup tg) {
super((tg != null) ? tg : Thread.currentThread().getThreadGroup(),
nextThreadName());
}
/**
* construct a thread in the default ThreadGroup with a few
* options set
*
* @param isDaemon <code>true</code> means be a daemon thread,
* <code>false</code> means don't.
* @param priority the value to use when calling setPriority
* @param autoStart <code>true</code> means call this.start()
* @see java.lang.Thread#start()
*/
public RunQueue(boolean isDaemon, int priority, boolean autoStart) {
this(null, isDaemon, priority, autoStart);
}
/**
* construct a thread in the default ThreadGroup with a few
* options set
*
* @param tg the ThreadGroup to be in
* @param isDaemon <code>true</code> means be a daemon thread,
* <code>false</code> means don't.
* @param priority the value to use when calling setPriority
* @param autoStart <code>true</code> means call this.start()
* @see java.lang.Thread#start()
*/
public RunQueue(ThreadGroup tg, boolean isDaemon, int priority,
boolean autoStart) {
super(tg, nextThreadName());
setDaemon(isDaemon);
setPriority(priority);
if (autoStart) {
start();
}
}
/**
* start going. This function locks the queue, dequeues and item,
* unlocks the queue, and calls run on the object that was
* dequeued. if no object was on the queue, it waits on the queue.
* this function never exits.
*/
public void run() {
while (true) {
Runnable r = null;
synchronized (queue) { //lock the queue
while (queue.isEmpty()) {
try {
queue.wait(); //wait for an enqueue to happen
} catch (java.lang.InterruptedException e) {
e.printStackTrace();
}
}
r = queue.remove(queue.size() - 1);
}
try {
r.run();
} catch (Exception e) {
//Since this happens asynchronously to the thread who
// enqueued
//the object, there isn't a whole lot we can do...
e.printStackTrace();
}
}
}
/**
* Add an object to the queue of threads to run
*
* @param r the object to add
*/
public void enqueue(TerminatingRunnable r) {
synchronized (queue) {
queue.add(r);
queue.notifyAll(); //notify the running thread that the
// queue
// has stuff in it now
}
}
/**
* if we use threadgroups, we need names. So here's where we make
* them
*/
private static synchronized String nextThreadName() {
return ("RunQueueThread-" + tcount++);
}
}