Class SequentialTask
- java.lang.Object
-
- net.sf.eBus.util.SequentialTask
-
- All Implemented Interfaces:
Runnable
public final class SequentialTask extends Object implements Runnable
When using a thread pool to execute tasks there is no guarantee the tasks will be executed in the same sequential order as offered to the pool. If the tasks are independent of each other, then order is unimportant. But if the tasks are chronologically dependent and must be exected in order, then the lack of guaranteed order is problematic.SequentialTaskoffers 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
createTaskto be garbage collected and automatically removed from the task object index map.Example Use: The Observer Pattern
In the Observer Pattern (GoF pp. 293 - 299) the Subject class'Notify()method calls back observers:
This callback can be converted from updating each observer in turn to a multi-threaded approach using apublic void Notify() { for (Observers o: observers) { o.Update(); } }thread poolto execute each callback:
The above code is acceptable if callback ordering is not a factor. Consider the following code;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(); } }); } }
If it does not matter if// 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()s1updates an observer befores0's update for the same observer, then using the above thread pool solution is acceptable. But ifs0's update must occur befores1's update, then the threads must be serialized.SequentialTaskprovides 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 too.Update()is guaranteed to occur befores1'so.Update(). However calls toUpdate()for different observers can execute in parallel. Only updates to the same observer are serialized.- Author:
- Charles Rapp
-
-
Method Summary
All Methods Static Methods Instance Methods Concrete Methods Modifier and Type Method Description static SequentialTaskcreateTask(Object o, Runnable task)Creates a sequential task for the given object and task.static SequentialTaskcreateTask(Object o, Runnable task, Logger logger, Level logLevel)Creates a sequential task for the given object and task.intindex()Returns the task's run index.voidrun()Synchronizes on the task index waiting for its turn to run the user task.
-
-
-
Method Detail
-
run
public void run()
Synchronizes on the task index waiting for its turn to run the user task. Once the index is reached, the user task is executed. Once execution completes, the task index is incremented and waiting sequential tasks are notified concerning the new current index.If the user task throws an exception, it is caught and reported via the supplied logger at the specified level.
-
index
public int index()
Returns the task's run index.- Returns:
- the task's run index.
-
createTask
public static SequentialTask createTask(Object o, Runnable task)
Creates a sequential task for the given object and task. Iftaskthrows an exception, it will be caught and quietly ignored.- Parameters:
o- The task is associated with this object.task- Runs this user task.- Returns:
- A sequential task associated with
oand executestask. - Throws:
IllegalArgumentException- if eitheroortaskisnull.
-
createTask
public static SequentialTask createTask(Object o, Runnable task, Logger logger, Level logLevel)
Creates a sequential task for the given object and task. Iftaskthrows an exception, it will be logged tologgeratlogLevel.- Parameters:
o- The task is associated with this object.task- Runs this user task.logger- Iftaskthrows an exception, then report it via this logger.logLevel- Reporttaskexception at this log level.- Returns:
- A sequential task associated with
oand executestask. - Throws:
IllegalArgumentException- if eitheroortaskisnull.
-
-