Fields Summary |
---|
public static final String | RUNNINGThe queue is in the processes of running tasks. |
public static final String | SUSPENDINGThe queue may still be running tasks but as soon as possible
will go to SUSPENDED state. |
public static final String | SUSPENDEDThe queue is no longer running any tasks and will not
run any tasks until resumeExecution is called. |
public static final String | TERMINATEDThis queue has been interrupted |
protected static RunnableQueue | defaultQueueThe default RunnableQueue instance. |
protected String | stateThe Suspension state of this thread. |
protected Object | stateLockObject to synchronize/wait/notify for suspension
issues. |
protected Scheduler | schedulerThe Scheduler which can run Runnables at a fixed
rate. |
protected DoublyLinkedList | listThe Runnable objects list, also used as synchoronization point
for pushing/poping runables. |
protected RunnableQueueHandler | queueHandlerThe object which handles RunnableQueue events. |
protected Thread | runnableQueueThreadThe current thread. |
private static int | threadCountUsed for the RunnableQueue's thread names. |
Methods Summary |
---|
public static com.sun.perseus.util.RunnableQueue | createRunnableQueue(com.sun.perseus.util.RunnableQueue$RunnableQueueHandler queueHandler)Creates a new RunnableQueue started in a new thread.
RunnableQueue result = new RunnableQueue();
// Configure the RunHandler
if (queueHandler == null) {
queueHandler = new VoidQueueHandler();
}
result.queueHandler = queueHandler;
// Start the thread. We use the RunnableQueue instance as
// a lock to synchronize between this method and the
// run method (called from the RunnableQueue thread)
synchronized (result) {
Thread t = new Thread(result, "RunnableQueue-" + threadCount++);
ThreadSupport.setDaemon(t, true);
t.setPriority(Thread.MIN_PRIORITY);
t.start();
while (result.getThread() == null) {
try {
// See the run() method. It calls notify on
// the RunnableQueue instance to notify us
// that the thread has started executing
result.wait();
} catch (InterruptedException ie) {
}
}
}
// Wait until we get into suspended state. State changes
// are synchronized with the stateLock lock.
synchronized (result.stateLock) {
try {
while (result.state != SUSPENDED) {
result.stateLock.wait();
}
} catch (InterruptedException ie) {
}
}
return result;
|
public void | empty()Removes all pending Runnable s.
synchronized (list) {
list.empty();
}
|
public static com.sun.perseus.util.RunnableQueue | getDefault()Returns the default RunnableQueue instance. This is what
should be used in most circumstances. In particular, all document
instances which need to process in a seperate thread should share this
default RunnableQueue.
if (defaultQueue != null) {
return defaultQueue;
}
defaultQueue = RunnableQueue.createRunnableQueue(new VoidQueueHandler());
defaultQueue.resumeExecution();
return defaultQueue;
|
public java.lang.Runnable | getNextPending()
synchronized (list) {
if (list.getSize() == 0) {
return null;
} else {
return ((Link) list.getHead()).runnable;
}
}
|
public java.lang.String | getQueueState()
synchronized (stateLock) {
return state;
}
|
public int | getSize()
synchronized (list) {
return list.getSize();
}
|
public java.lang.Thread | getThread()Returns the thread in which the RunnableQueue is currently running.
return runnableQueueThread;
|
public void | invokeAndWait(java.lang.Runnable r, com.sun.perseus.util.RunnableQueue$RunnableHandler runHandler)Waits until the given Runnable's run() has returned.
Note: invokeAndWait() must not be called from the
current thread (for example from the run() method of the
argument).
if (runnableQueueThread == null) {
throw new IllegalStateException
("RunnableQueue not started or has exited");
}
if (runnableQueueThread == Thread.currentThread()) {
throw new IllegalStateException
("Cannot be called from the RunnableQueue thread");
}
LockableLink l = new LockableLink(r, runHandler);
synchronized (list) {
list.push(l);
list.notify();
}
l.lock();
|
public void | invokeLater(java.lang.Runnable r, com.sun.perseus.util.RunnableQueue$RunnableHandler runHandler)Schedules the given Runnable object for a later invocation, and
returns.
An exception is thrown if the RunnableQueue was not started.
if (runnableQueueThread == null) {
throw new IllegalStateException
("RunnableQueue not started or has exited");
}
synchronized (list) {
list.push(new Link(r, runHandler));
list.notify();
}
|
public void | preemptAndWait(java.lang.Runnable r, com.sun.perseus.util.RunnableQueue$RunnableHandler runHandler)Waits until the given Runnable's run() has returned.
The given runnable preempts any runnable that is not currently
executing (ie the next runnable started will be the one given).
Note: preemptAndWait() must not be called from the
current thread (for example from the run() method of the
argument).
if (runnableQueueThread == null) {
throw new IllegalStateException
("RunnableQueue not started or has exited");
}
if (runnableQueueThread == Thread.currentThread()) {
throw new IllegalStateException
("Cannot be called from the RunnableQueue thread");
}
LockableLink l = new LockableLink(r, runHandler);
synchronized (list) {
list.unpop(l);
list.notify();
}
l.lock();
|
public void | preemptLater(java.lang.Runnable r, com.sun.perseus.util.RunnableQueue$RunnableHandler runHandler)Schedules the given Runnable object for a later invocation, and
returns. The given runnable preempts any runnable that is not
currently executing (ie the next runnable started will be the
one given). An exception is thrown if the RunnableQueue was
not started.
if (runnableQueueThread == null) {
throw new IllegalStateException
("RunnableQueue not started or has exited");
}
synchronized (list) {
list.unpop(new Link(r, runHandler));
list.notify();
}
|
public void | resumeExecution()Resumes the execution of this queue.
if (runnableQueueThread == null) {
throw new IllegalStateException
("RunnableQueue not started or has exited");
}
synchronized (stateLock) {
if (state != RUNNING) {
state = RUNNING;
stateLock.notifyAll(); // wake it up.
try {
// Wait until we have really resumed
stateLock.wait();
} catch (InterruptedException ie) {
// The calling thread was interrupted
}
}
}
|
public void | run()Runs this queue. Implements the Runnable interface.
//
// This object is used as a lock to synchronize on the
// queue's thread execution start.
//
synchronized (this) {
runnableQueueThread = Thread.currentThread();
// Wake the create method so it knows we are in
// our run and ready to go.
notify();
}
Link l = null;
Runnable rable = null, sRable;
long t = 0;
long wait = 0;
try {
while (!ThreadSupport.isInterrupted(Thread.currentThread())) {
// Mutex for suspending/resuming work.
synchronized (stateLock) {
if (state != RUNNING) {
state = SUSPENDED;
// notify suspendExecution in case it is
// waiting til we shut down.
stateLock.notifyAll();
queueHandler.executionSuspended(this);
while (state != RUNNING) {
state = SUSPENDED;
// Wait until resumeExecution called.
stateLock.wait();
}
// notify resumeExecution as it waits until
// execution are really resumed
stateLock.notifyAll();
queueHandler.executionResumed(this);
}
}
// First, run the Scheduler to take care of all the pending
// fixed rate Runnables.
t = System.currentTimeMillis();
scheduler.run(t);
synchronized (list) {
l = (Link) list.pop();
if (l == null) {
// Wait until the next scheduled runnable
wait = scheduler.nextRun(System.currentTimeMillis());
if (wait == 0) {
wait = 1;
}
if (state == SUSPENDING) {
continue;
}
if (wait > 0) {
list.wait(wait);
} else {
// There is no scheduled runnable at this point.
list.wait();
}
continue; // start loop over again...
}
rable = l.runnable;
}
try {
rable.run();
} catch (Exception e) {
// Might be nice to notify someone directly.
// But this is more or less what Swing does.
e.printStackTrace();
}
if (l.runHandler != null) {
l.runHandler.runnableInvoked(this, rable);
}
l.unlock();
rable = null;
}
} catch (InterruptedException e) {
if (this == defaultQueue) {
defaultQueue = null;
}
e.printStackTrace();
} finally {
if (this == defaultQueue) {
defaultQueue = null;
}
System.err.println(">>>>>>>>>>>>>> RunnableQueue terminating");
synchronized (this) {
runnableQueueThread = null;
}
synchronized (stateLock) {
state = TERMINATED;
stateLock.notifyAll();
}
}
|
public void | safeInvokeAndWait(java.lang.Runnable r, com.sun.perseus.util.RunnableQueue$RunnableHandler runHandler)Waits until the given Runnable's run() has returned.
Note: safeInvokeAndWait() may be called from any thread.
This method checks if this thread is the update thread, in which case
the Runnable is invoked directly. Otherwise, it delegates to the
invokeAndWait method.
if (runnableQueueThread == Thread.currentThread()) {
r.run();
runHandler.runnableInvoked(this, r);
}
try {
invokeAndWait(r, runHandler);
} catch (InterruptedException ie) {
// We are in a bad state because the thread was interrupted while
// waiting for the runnable to complete.
throw new IllegalStateException();
}
|
public void | scheduleAtFixedRate(java.lang.Runnable r, com.sun.perseus.util.RunnableQueue$RunnableHandler runHandler, long interval)Schedules the input Runnable at the requested
fixed rate. The RunnableQueue offers a 'best'
effort service meaning that it will schedule the Runnable
as soon as possible so that the time between the begining of
two consecutive runs of the Runnable is as close
as possible to the requested rate. Note that a too high rate
may cause the rest of the Runnable in the
RunnableQueue to be starved and never get
executed.
scheduler.add(r, interval, runHandler);
// In case the queue is running and waiting for an item in the
// list, notify the list so that we can get the animation loop
// going. See the run() method.
synchronized (list) {
list.notify();
}
|
public void | suspendExecution(boolean waitTillSuspended)Suspends the execution of this queue after the current runnable
completes.
if (runnableQueueThread == null) {
throw new IllegalStateException
("RunnableQueue not started or has exited");
}
synchronized (stateLock) {
if (state == SUSPENDED) {
// already suspended...
return;
}
if (state == RUNNING) {
state = SUSPENDING;
synchronized (list) {
// Wake up run thread if it is waiting for jobs,
// so we go into the suspended case (notifying
// run-handler etc...)
list.notify();
}
}
if (waitTillSuspended) {
try {
stateLock.wait();
} catch (InterruptedException ie) { }
}
}
|
public void | unschedule(java.lang.Runnable r)Removes the input Runnable from the list of
Runnables scheduled at a fixed rate. If the Runnable is not
currently scheduled at a fixed rate, then this method does
nothing. If this Runnable was scheduled multiple times
with this RunnableQueue, then all instances are removed.
scheduler.remove(r);
|