public final class SequentialTask
extends java.lang.Object
implements java.lang.Runnable
SequentialTask
offers a solution between a dedicated
event thread and a thread pool. Tasks associated with the
same object are forced to execute in sequential order.
Each task is assigned an index based on its associated object
and executes only when its index becomes the current index.
Otherwise, the task waits for its index to be reached. When
the task completes, the current index is incremented and all
waiting sequential tasks are notified of the new index.
By associating the task index with an object, it is possible
for multiple tasks associated with different objects to
execute simultaneously. Only tasks associated with the same
object are forced to execute serially. A weak hash map is used
to associate an object with its task index values. This allows
objects passed to
createTask
to be
garbage collected and automatically removed from the task
object index map.
Notify()
method calls back observers:
public void Notify()
{
for (Observers o: observers)
{
o.Update();
}
}
This callback can be converted from updating each observer in
turn to a multi-threaded approach using a
thread pool
to
execute each callback:
public void Notify()
{
Iterator<Observer> oit;
for (oit = observers.iterator(); oit.hasNext();)
{
// The run task requires that the Observer local
// variable be final. Hence using an iterator and
// declaring the variable within the for body.
final Observer o = oit.next();
threadPool.execute(
new Runnable()
{
@Override
public void run()
{
o.Update();
}
});
}
}
The above code is acceptable if callback ordering is not a
factor. Consider the following code;
// s0 and s1 are both Subject instances. Assume that their
// respective observer lists have some observer instances in
// common (that is, a non-null intersection of observers).
s0.Notify();
s1.Notify()
If it does not matter if s1
updates an observer before
s0
's update for the same observer, then using the
above thread pool solution is acceptable. But if s0
's
update must occur before s1
's update, then the threads
must be serialized. SequentialTask
provides this
capability:
public void Notify()
{
Iterator<Observer> oit;
for (oit = observers.iterator(); oit.hasNext();)
{
// The run task requires that the Observer local
// variable be final. Hence using an iterator and
// declaring the variable within the for body.
final Observer o = oit.next();
threadPool.execute(
SequentialTask.createTask(
o,
new Runnable()
{
@Override
public void run()
{
o.Update();
}
}
});
}
}
s0
's call to o.Update()
is guaranteed to
occur before s1
's o.Update()
. However calls
to Update()
for different observers can execute in
parallel. Only updates to the same observer are serialized.Modifier and Type | Method and Description |
---|---|
static SequentialTask |
createTask(java.lang.Object o,
java.lang.Runnable task)
Creates a sequential task for the given object and task.
|
static SequentialTask |
createTask(java.lang.Object o,
java.lang.Runnable task,
java.util.logging.Logger logger,
java.util.logging.Level logLevel)
Creates a sequential task for the given object and task.
|
int |
index()
Returns the task's run index.
|
void |
run()
Synchronizes on the task index waiting for its turn to
run the user task.
|
public void run()
If the user task throws an exception, it is caught and reported via the supplied logger at the specified level.
run
in interface java.lang.Runnable
public int index()
public static SequentialTask createTask(java.lang.Object o, java.lang.Runnable task)
task
throws an exception, it will be caught and
quietly ignored.o
- The task is associated with this object.task
- Runs this user task.o
and
executes task
.java.lang.IllegalArgumentException
- if either o
or task
is null
.public static SequentialTask createTask(java.lang.Object o, java.lang.Runnable task, java.util.logging.Logger logger, java.util.logging.Level logLevel)
task
throws an exception, it will be logged
to logger
at logLevel
.o
- The task is associated with this object.task
- Runs this user task.logger
- If task
throws an exception, then
report it via this logger.logLevel
- Report task
exception at this
log level.o
and
executes task
.java.lang.IllegalArgumentException
- if either o
or task
is null
.Copyright © 2001 - 2024. Charles W. Rapp. All rights reserved.