|
Forward Computing and Control Pty. Ltd. Threads Package V1.0.3 2005/04/11 |
|||||||
PREV CLASS NEXT CLASS | FRAMES NO FRAMES | |||||||
SUMMARY: NESTED | FIELD | CONSTR | METHOD | DETAIL: FIELD | CONSTR | METHOD |
java.lang.Objectau.com.forward.threads.ThreadReturn
public class ThreadReturn
This is the main class of this package and contains the static methods for handling threads.
This class contains a number
of static
methods that allow you to
ThreadReturn.save(Object)
and ThreadReturn.join()
ThreadReturn.save(Object)
and ThreadReturn.join()
interrupt()
method, ThreadReturn.ifInterruptedStop()
ThreadListener
s threads to be called when the thread has died,
ThreadReturn.addListener(Thread, ThreadListener)
Provided you add the following acknowledgement
This program incorporates code provided by Forward Computing and Control Pty. Ltd., www.forward.com.auyou may re-distribute the compiled java .class file in both private and commercial products.
try/catch
block in the
thread's run()
method and the addition of ThreadReturn.save(Object)
and ThreadReturn.ifInterruptedStop()
statements.
Here is an example of a Thread
class run()
method that follows this outline.
public class ExampleThread {
public void run() {
// put a try/catch at the outermost level
try {
// your thread code goes here
// do some work ...
// ...
// stop this thread if it has been interrupted
ThreadReturn.ifInterruptedStop();
// do some more work ...
// ...
// stop this thread if it has been interrupted
ThreadReturn.ifInterruptedStop();
// .....
ThreadReturn.save(result); // optional if you want to return a result
} catch (Throwable e) {
// catch all exceptions, errors etc. thrown by this thread here
ThreadReturn.save(e);
}
}
}
As well as, this you must insure that all fatal errors that occur in methods called by the run()
method throw an exception back up to the run()
method to be caught by the} catch (Throwable e) {
Then in the parent thread, you can use the following code to wait until the sub-thread dies and collect the result.
Object threadResult = null;
Thread t1 = new ExampleThread();
t1.start();
try {
threadResult = ThreadReturn.join(t1);
} catch (InterruptedException ex) {
// some error running t1, handle it here
if (ex instanceof ThreadException) {
// t1 throw a Throwable which is the cause of this ThreadException
} else {
// ThreadReturn.join(t1) was interrupted
}
}
Like the Thread
class join()
method that ThreadReturn.join(t1)
is replacing,
ThreadReturn.join(t1)
can throw an InterruptedException
. If the thread t1
's run()
terminated because a Throwable
was caught in its catch (Throwable e)
clause,
then ThreadReturn.join(t1)
will throw a ThreadException
with that
Throwable
stored as it cause. ex.getCause()
will retrieve it or you can
use StackTrace.toString(ex)
to get the whole stacktrace as a String
.
The result returned by
threadResult = ThreadReturn.join(t1);
is the Object
saved by the
ThreadReturn.save(result);
statement at the end of the run()
method (just above the
} catch (Throwable e) {
line.
If you did not put this statement in your run()
method
ThreadReturn.join(t1);
will return null
To wait at most x milliseconds for the sub-thread to time out you can use one of the two versions of
ThreadReturn.join
that specify a timeout, ThreadReturn.join(Thread, long)
or
ThreadReturn.join(Thread, long, int)
e.g. to wait at
most 500
milliseconds
Object threadResult = null;
Thread t1 = new ExampleThread();
t1.start();
try {
threadResult = ThreadReturn.join(t1, 500);
} catch (InterruptedException ex) {
// some error running t1, handle it here
if (ex instanceof ThreadException) {
// t1 throw a Throwable which is the cause of this ThreadException
} else if (ex instanceof TimedOutdException) {
// join timedout before t1 died
} else {
// ThreadReturn.join(t1) was interrupted
}
}
In this case ThreadReturn.join(t1,500)
can also throw a TimedOutException
to indicate
the thread did not finish in the specified time.
ThreadReturn.stop(thread);
.
If the thread in is not blocked then its interrupted status will be set and the next time it
executes a ThreadReturn.ifInterruptedStop()
statement an InterruptedException
will be thrown causing the run()
method to terminate.
If the thread is waiting in a wait()
, join()
or sleep()
then an InterruptedException
will be thrown.
If the thread is blocked in an I/O operation on a java.nio.channels.interruptibleChannel
then a ClosedByInterruptException
will be thrown.
Any of these cases will cause the run()
method to terminate.
Using ThreadReturn.stop(thread);
instead of thread.interrupt();
has the following
advantages.
i)thread.interrupt();
will not set the interrupt flag for threads that have not started yet.
ii)ThreadReturn.stop(thread);
will continue to interrupt the thread until it dies. This
overcomes problems where a method called by the thread's run()
method catches and ignores the first interrupt()
call.
All the versions of ThreadReturn.join()
call the thread's interrupt()
method before they return, even if an exception is being thrown. This means that if you have written
your thread's run()
method according to the guidelines above your thread will be terminated
if ThreadReturn.join()
throws any exception.
ThreadListener
s to a thread using the ThreadReturn.addListener(Thread, ThreadListener)
method. Classes implementing the ThreadListener
interface have three methods ThreadListener.threadResult(ThreadEvent)
,
ThreadListener.threadInterrupted(ThreadEvent)
and ThreadListener.threadError(ThreadEvent)
.
If the thread terminates normally, threadResult(ThreadEvent)
is called with a ThreadEvent
containing the source thread, a type of ThreadEvent.RETURN
and
the result Object
saved by the thread, if any.
If the threadResult(ThreadEvent)
method
throws any Throwable
object, it is passed onto that listener's
threadError(ThreadEvent)
method. Errors in one listener's
ThreadListener.threadError(ThreadEvent)
method do not effect the
processing of other listeners registered for this thread.
NOTE:threadResult(ThreadEvent)
should not modify the
result Object
contained in the ThreadEvent
because the same result Object
will be passed on to the other registered listeners for this thread.
If the thread terminates and has saved an InterruptedException
or a
ClosedByInterruptException
, then
threadInterrupted(ThreadEvent)
is called with a ThreadEvent
containing the source thread, a type of ThreadEvent.INTERRUPTED
and
the Exception
saved by the thread.
If the threadInterrupted(ThreadEvent)
method
throws any Throwable
object, it is passed onto that listener's
threadError(ThreadEvent)
method. Errors in one listener's
ThreadListener.threadError(ThreadEvent)
method do not effect the
processing of other listeners registered for this thread.
NOTE:threadInterrupted(ThreadEvent)
should not modify the
result Object
contained in the ThreadEvent
because the same Exception
will be passed on to the other registered listeners for this thread.
If the thread terminates and has saved some other type of Throwable
or if the system monitor thread
is interrupted or there is some other error, then threadError(ThreadEvent)
is called with a ThreadEvent
containing the source thread, a type of ThreadEvent.ERROR
and
the Throwable
object that was thrown.
If the threadError(ThreadEvent)
method
throws any Throwable
objects, they are caught and ignored.
It is your responsibility to catch and handle ALL
Throwable
objects thrown by this method.
ThreadListener
s can be added (or removed) at any time.
If a ThreadListener
is added before the thread is started, the thread is added to the list which is checked every
getCheckDelay()
milliseconds. When the thread has started (or has died), a monitor
thread is started and joins the thread waiting for it to finish. When the thread has died,
all the registered ThreadListener
s are called and removed.
Because a thread can only be run once, each listener is removed when it is called.
If a ThreadListener
is added after the thread has started (or after it has died), a monitor
thread is started and joins the thread waiting for it to finish. When the thread has died,
all the registered ThreadListener
s are called and removed.
NOTE:
i) All ThreadListener
methods are called on a monitor thread that is neither
the thread being listened to nor the thread that added the listener.
ii) If you add a ThreadListener
after the thread has died, the monitor thread will
call the ThreadListener
as soon as it starts and passes the ThreadListener
,
either the Object
the thread returned, or the Throwable
that was thrown.
ThreadReturn.addListener(Thread,ThreadListener)
method, no additional threads are started by this package. However when you add a ThreadListener
, a
monitor thread is started for each thread that has listeners. This monitor thread calls
join(java.lang.Thread)
to detect when the thread has died and then calls the ThreadListener
s
registered for that thread. The monitor thread then dies.
If you add a ThreadListener
to a thread that has not started then a single daemon check thread is
started. Once started this check thread continues to run until the application terminates.
The check thread goes to sleep
for the number of milliseconds set by setCheckDelay(long)
(default 100mS) and then checks
if any of the threads with listeners have started since the last check. For any that have started, or have
started and died, since the last check, the check thread starts a monitor thread to handle that thread's
listeners. It then loops to sleep
again.
ThreadReturn.debug
to true
, debugging messages
will be sent to System.out
.
ThreadReturn.saveImmedeately
to true
to force listeners to be called as soon as Thread.save()
is called for the first time without waiting for the thread to die and the check thread to notice it.
The listeners will be called in the running thread and then removed so subsequent calls
to Thread.save() from this thread will NOT fire listeners. However the final result stored
will be that from the last Thread.save(), so only have one Thread.save() at the bottom of the
try{} block and one other in the catch(){} block, to ensure consistent results.
Field Summary | |
---|---|
static boolean |
debug
Set this flag to true to output debugging messages to System.out |
static boolean |
saveImmedeately
Set this flag to true to force listeners to be called as soon as Thread.save()
is called for the first time without waiting for the thread to die and the check thread to notice it. |
Method Summary | |
---|---|
static void |
addListener(java.lang.Thread thread,
ThreadListener listener)
Adds a listener for a thread. |
static long |
getCheckDelay()
Gets the loop delay for the check thread that checks on threads waiting to be started. |
static boolean |
hasDied(java.lang.Thread thread)
Checks if this thread has died |
static void |
ifInterruptedStop()
Calls yield() on the current thread and then throws an InterruptedException
if the thread's interrupted state is set. |
static java.lang.Object |
join(java.lang.Thread thread)
Waits for a thread to die and returns the Object it saved. |
static java.lang.Object |
join(java.lang.Thread thread,
long milliSecs)
Waits at most milliSecs for a thread to die and returns the Object
it saved. |
static java.lang.Object |
join(java.lang.Thread thread,
long milliSecs,
int nanoSecs)
Waits at most milliSecs+nanoSecs for a thread to die and returns the Object it saved. |
static void |
removeListener(java.lang.Thread thread,
ThreadListener listener)
Removes a listener from a thread, if the listener has not already been removed. |
static void |
save(java.lang.Object obj)
Saves this Object against the current thread. |
static void |
setCheckDelay(long millisecs)
Sets the loop delay for the check thread that checks on threads waiting to be started. |
static void |
stop(java.lang.Thread thread)
Sets the stop flag for this thread in the threadStopMap and calls the
thread's interrupt() method. |
Methods inherited from class java.lang.Object |
---|
clone, equals, finalize, getClass, hashCode, notify, notifyAll, toString, wait, wait, wait |
Field Detail |
---|
public static boolean debug
true
to output debugging messages to System.out
public static boolean saveImmedeately
true
to force listeners to be called as soon as Thread.save()
is called for the first time without waiting for the thread to die and the check thread to notice it.
The listeners will be called in the running thread and then removed so subsequent calls
to Thread.save() from this thread will NOT fire listeners. However the final result stored
will be that from the last Thread.save(), so only have one Thread.save() at the bottom of the
try{} block and one other in the catch(){} block, to ensure consistent results.
Method Detail |
---|
public static void setCheckDelay(long millisecs)
millisecs
- the delay, in milliseconds, between checking if threads with listeners have been stared.public static long getCheckDelay()
public static boolean hasDied(java.lang.Thread thread)
public static void addListener(java.lang.Thread thread, ThreadListener listener)
ThreadListener
is only called once, when the
thread has died, and then discarded, because threads can only be run once.
The same listener cannot be added twice for the same thread.
All calls to this listener are made by a separate monitor thread. I.e.
the monitor thread is neither the thread
being listened to, nor the thread calling this method.
getCheckDelay()
milliseconds to see when it starts.
When the thread has started, the monitor thread joins it and waits for it to die
and then calls the listener and discards it.
thread
- the thread to listen for its death.listener
- the ThreadListener
to call when the
thread has died.public static void removeListener(java.lang.Thread thread, ThreadListener listener)
thread
- the thread to remove the listener from.listener
- the ThreadListener
to remove. If the
ThreadListener
is no longer registered for this thread
, this method
just returns.public static void stop(java.lang.Thread thread)
threadStopMap
and calls the
thread's interrupt()
method.
Then each time the listener thread runs interrupt is called again until the thread dies
public static void ifInterruptedStop() throws java.lang.InterruptedException
yield()
on the current thread and then throws an InterruptedException
if the thread's interrupted state is set.
This method does not clear the thread's interrupt state.
java.lang.InterruptedException
- if current thread's
interrupt state is set.public static void save(java.lang.Object obj)
Object
against the current thread.
If the object saved is not a Throwable
,
then the object will be returned by the ThreadReturn.join()
methods and will be
passed in a ThreadEvent
to the ThreadListener.threadResult(ThreadEvent)
method of
ThreadListener
s registered for the thread.
If the object is an InterruptedException
or a
ClosedByInterrupteException
, then the ThreadReturn.join()
methods
will throw a ThreadInterruptedException
and the object saved will be
passed in a ThreadEvent
to the ThreadListener.threadInterrupted(ThreadEvent)
method of
ThreadListener
s registered for the thread.
If the object saved is any other Throwable
, then the ThreadReturn.join()
methods
will throw a ThreadException
and the Throwable
will be
passed in a ThreadEvent
to the ThreadListener.threadError(ThreadEvent)
method of
ThreadListener
s registered for the thread.
If this method is called more than once by the same thread, only the last Object
saved will be returned.
obj
- the Object
to be save by the current thread.public static java.lang.Object join(java.lang.Thread thread) throws java.lang.InterruptedException
Object
it saved.
If the Object
saved by the thread, using ThreadReturn.save(Object)
,
is a Throwable
object, then this method throws a ThreadException
, otherwise the
Object
saved is returned by this method.
If this method is interrupted, an InterruptedException
is thrown.
thread
- the thread to wait for.
Object
saved by the thread, or null
if none saved.
ThreadInterruptedException
- thrown if the exception saved by the thread was
InterruptedException
or ClosedByInterruptException
ThreadException
- thrown if some other Throwable
was saved by the thread
java.lang.InterruptedException
- thrown if the thread calling this method was interrupted.
java.lang.IllegalThreadStateException
- thrown if the thread has already died
or has not been started or has been re-started after it has died.public static java.lang.Object join(java.lang.Thread thread, long milliSecs) throws java.lang.InterruptedException
milliSecs
for a thread to die and returns the Object
it saved. To wait forever call with milliSecs equal to 0.
If the Object
saved by the thread, using ThreadReturn.save(Object)
,
is a Throwable
object, then this method throws a ThreadException
, otherwise the
Object
saved is returned by this method.
If this method is interrupted, an InterruptedException
is thrown.
If this method times out, a TimedOutException
is thrown.
thread
- the thread to wait for.milliSecs
- the milliSecs to wait for the thread
to die.
Object
saved by the thread, or null
if none saved.
ThreadInterruptedException
- thrown if the exception saved by the thread was
InterruptedException
or ClosedByInterruptException
ThreadException
- thrown if some other Throwable
was saved by the thread
TimedOutException
- thrown if this method timed out.
java.lang.InterruptedException
- thrown if the thread calling this method was interrupted.
java.lang.IllegalThreadStateException
- thrown if the thread has already died
or has not been started or has been re-started after it has died.public static java.lang.Object join(java.lang.Thread thread, long milliSecs, int nanoSecs) throws java.lang.InterruptedException
Object
it saved.
To wait forever call with milliSecs
and nanoSecs
equal to 0.
If the Object
saved by the thread, using ThreadReturn.save(Object)
,
is a Throwable
object, then this method throws a ThreadException
, otherwise the
Object
saved is returned by this method.
If this method is interrupted, an InterruptedException
is thrown.
If this method times out, a TimedOutException
is thrown.
thread
- the thread to wait for.milliSecs
- the milliSecs to wait for the thread
to die.nanoSecs
- the additional nanoSecs to wait (in
the range 0-999999).
Object
saved by the thread, or null
if none saved.
ThreadInterruptedException
- thrown if the exception saved by the thread was
InterruptedException
or ClosedByInterruptException
ThreadException
- thrown if some other Throwable
was saved by the thread
TimedOutException
- thrown if this method timed out.
java.lang.InterruptedException
- thrown if the thread calling this method was interrupted.
java.lang.IllegalThreadStateException
- thrown if the thread has already died
or has not been started or has been re-started after it has died.
|
Forward Computing and Control Pty. Ltd. Threads Package V1.0.3 2005/04/11 |
|||||||
PREV CLASS NEXT CLASS | FRAMES NO FRAMES | |||||||
SUMMARY: NESTED | FIELD | CONSTR | METHOD | DETAIL: FIELD | CONSTR | METHOD |