public final class SequentialTask extends Object implements Runnable
One solution is to use EventThread. Tasks submitted to
the thread the are guaranteed to be processed in sequential
order. This solution is acceptable if the thread is long lived
with new tasks routinely submitted. Event threads are a poor
solution if a large number of threads are required but new
events are posted infrequently to any one thread.
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() == true;)
{
// 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()
return;
}
});
}
}
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() == true;)
{
// 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()
return;
}
}
});
}
}
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(Object o,
Runnable task)
Creates a sequential task for the given object and task.
|
static SequentialTask |
createTask(Object o,
Runnable task,
Logger logger,
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.
public int index()
public static SequentialTask createTask(Object o, Runnable task) throws IllegalArgumentException
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.IllegalArgumentException - if either o or task is null.public static SequentialTask createTask(Object o, Runnable task, Logger logger, Level logLevel) throws IllegalArgumentException
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.IllegalArgumentException - if either o or task is null.Copyright © 2019. All rights reserved.