
Classes | |
| class | CancelableRunnable |
| class | TaskWrapper |
Public Types | |
| enum | ScheduleDelayMode { FIXED_RATE, FIXED_DELAY } |
Public Member Functions | |
| ThreadLoopRunner (Runnable task, long delayTime, TimeUnit unit, ThreadFactory tf, Logger logger) | |
| long | getDelayTimeMillis () |
| synchronized boolean | setDelayTime (long delayTime, TimeUnit unit) |
| ScheduleDelayMode | getDelayMode () |
| synchronized void | setDelayMode (ScheduleDelayMode delayMode) |
| synchronized void | runLoop () |
| synchronized boolean | isLoopRunning () |
| boolean | isTaskRunning () |
| boolean | isDisabled () |
| synchronized void | suspendLoop () |
| synchronized boolean | suspendLoopAndWait (long timeout, TimeUnit unit) throws InterruptedException |
| synchronized boolean | shutdown (long timeout, TimeUnit unit) throws InterruptedException |
Private Attributes | |
| final Logger | logger |
| final ScheduledExecutorService | runner |
| final TaskWrapper | taskWrapper |
| final AtomicBoolean | isDefunct |
| volatile ScheduleDelayMode | delayMode |
| volatile ScheduledFuture<?> | loop |
| volatile long | delayTimeNanos |
This class allows running some task repeatedly with a given delay. It is similar to the loop in C++ class ACS::Thread.
The code of the task to be executed gets passed to the constructor as a Runnable object. The time between executions is given in the constructor and can later be changed through setDelayTime(long, TimeUnit).
If the task takes some time to execute, you should consider implementing a soft cancel option. To do this, extend CancelableRunnable instead of simply implementing Runnable. When the action should be canceled (e.g. due to shutdown(long, TimeUnit)), the shouldTerminate flag will be set. Your code should check this flag at convenient times, and should return if the flag is set. Alternatively you can override the cancel method and terminate the task thread in different ways.
Method runLoop() starts the loop. Optionally the loop can be stopped with suspendLoop() or suspendLoopAndWait(long, TimeUnit), and can also be restarted with another call to runLoop(). To stop the loop for good, call shutdown(long, TimeUnit).
While the underlying classes from the JDK concurrent package could also be used directly, this class allows for shorter code that is also more similar to the style used in C++. Especially it imposes the limit of running one task repeatedly, which gives an easier API, at the expense of creating a separate instance of ThreadLoopRunner for some other repeated task. (The older JDK class java.util.Timer has problems recovering from errors and should not be used.)
| alma::acs::concurrent::ThreadLoopRunner::ThreadLoopRunner | ( | Runnable | task, | |
| long | delayTime, | |||
| TimeUnit | unit, | |||
| ThreadFactory | tf, | |||
| Logger | logger | |||
| ) | [inline] |
Creates a ThreadLoopRunner that can repeatedly execute task. The mode defaults to ScheduleDelayMode#FIXED_RATE unless being changed via setDelayMode(ScheduleDelayMode).
| task | user-supplied Runnable, or better subtype ThreadLoopRunner.CancelableRunnable. | |
| delayTime | ||
| unit | ||
| tf | ThreadFactory from which the loop thread will be created. | |
| logger | Logger used by this class. |
References delayMode, isDefunct, runner, setDelayTime(), and taskWrapper.
| ScheduleDelayMode alma::acs::concurrent::ThreadLoopRunner::getDelayMode | ( | ) | [inline] |
References delayMode.
Referenced by alma::acs::concurrent::ThreadLoopRunnerTest::testComplexWithSuspendAndRestart(), and alma::acs::concurrent::ThreadLoopRunnerTest::testSimple().
| long alma::acs::concurrent::ThreadLoopRunner::getDelayTimeMillis | ( | ) | [inline] |
References delayTimeNanos.
Referenced by alma::acs::concurrent::ThreadLoopRunnerTest::testSetDelayTimeAndMode().
| boolean alma::acs::concurrent::ThreadLoopRunner::isDisabled | ( | ) | [inline] |
Returns true after shutdown(long, TimeUnit) was called. Then invoking any control method of this class will throw an IllegalStateException.
References isDefunct.
Referenced by alma::acs::concurrent::ThreadLoopRunnerTest::testComplexWithSuspendAndRestart(), and alma::acs::concurrent::ThreadLoopRunnerTest::testSimple().
| synchronized boolean alma::acs::concurrent::ThreadLoopRunner::isLoopRunning | ( | ) | [inline] |
true if the loop is running, regardless of whether the task is currently being executed. References loop.
Referenced by runLoop(), setDelayMode(), setDelayTime(), alma::acs::concurrent::ThreadLoopRunnerTest::testComplexWithSuspendAndRestart(), alma::acs::concurrent::ThreadLoopRunnerTest::testSetDelayTimeAndMode(), and alma::acs::concurrent::ThreadLoopRunnerTest::testSimple().
| boolean alma::acs::concurrent::ThreadLoopRunner::isTaskRunning | ( | ) | [inline] |
true if the task is running, regardless of whether the loop is still running or has been stopped already. References alma::acs::concurrent::ThreadLoopRunner::TaskWrapper::isRunning, and taskWrapper.
Referenced by runLoop(), and alma::acs::concurrent::ThreadLoopRunnerTest::testSetDelayTimeAndMode().
| synchronized void alma::acs::concurrent::ThreadLoopRunner::runLoop | ( | ) | [inline] |
Runs the loop, either for the first time, or after a call to suspendLoop().
| IllegalStateException | if the loop is already running, or if the run() method of a previous loop is still executing, or after shutdown |
References delayMode, delayTimeNanos, isDefunct, isLoopRunning(), isTaskRunning(), loop, runner, and taskWrapper.
Referenced by setDelayTime(), alma::acs::concurrent::ThreadLoopRunnerTest::testComplexWithSuspendAndRestart(), alma::acs::concurrent::ThreadLoopRunnerTest::testSetDelayTimeAndMode(), and alma::acs::concurrent::ThreadLoopRunnerTest::testSimple().
| synchronized void alma::acs::concurrent::ThreadLoopRunner::setDelayMode | ( | ScheduleDelayMode | delayMode | ) | [inline] |
Sets the delay mode to be used for the next runLoop().
This method must not be called when the loop is already running (see isLoopRunning()), in which case it throws an IllegalStateException. The reason for this is that we see no need to change this mode on the fly, and rather avoid the overhead of automatically stopping and restarting the loop with the possible complications if the run() method does not terminate. Also we don't want getDelayMode() to give results that are not correct for the currently running loop. Note that the same issue is handled differently in setDelayTime(long, TimeUnit) where it seems desirable to change the delay time while the loop is running.
| delayMode | FIXED_RATE or FIXED_DELAY, see ScheduledExecutorService#scheduleAtFixedRate(Runnable, long, long, TimeUnit) and ScheduledExecutorService#scheduleWithFixedDelay(Runnable, long, long, TimeUnit). Note that the C++ implementation uses equivalent of FIXED_RATE. |
| IllegalStateException | if called when the loop is running, or after shutdown. |
References isDefunct, and isLoopRunning().
Referenced by alma::acs::concurrent::ThreadLoopRunnerTest::testComplexWithSuspendAndRestart(), and alma::acs::concurrent::ThreadLoopRunnerTest::testSetDelayTimeAndMode().
| synchronized boolean alma::acs::concurrent::ThreadLoopRunner::setDelayTime | ( | long | delayTime, | |
| TimeUnit | unit | |||
| ) | [inline] |
Sets the time between calls to the loop action object, where the time for the task itself is included or not, depending on the set ScheduleDelayMode.
If this method is called while the thread loop is already running, it will wait for the current task to finish and then reschedule the actions at the new rate. If the currently running task fails to finish after 10 seconds, a warning is logged and false is returned.
Note that it is a limitation in the underlying ScheduledThreadPoolExecutor that the delay time cannot be changed without stopping and restarting the loop. If this becomes a problem, we could use the concurrent lib classes in a more customized way.
| delayTime | new delay time | |
| unit |
References delayTimeNanos, isDefunct, isLoopRunning(), logger, runLoop(), and suspendLoopAndWait().
Referenced by alma::acs::concurrent::ThreadLoopRunnerTest::testSetDelayTimeAndMode(), and ThreadLoopRunner().
| synchronized boolean alma::acs::concurrent::ThreadLoopRunner::shutdown | ( | long | timeout, | |
| TimeUnit | unit | |||
| ) | throws InterruptedException [inline] |
Shuts down this thread loop runner, attempting to gracefully stop the running task if CancelableRunnable was provided, or otherwise letting the currently running loop action finish.
The ThreadLoopRunner cannot be used any more after this method has been called. (Then will return true, other methods will throw IllegalStateException.) The timeout refers to how long this method waits for the task to terminate. If it terminates before the given timeout, then true is returned, otherwise false which means that the Runnable action object is still in use and should not be reused later unless it is re-entrant.
| timeout | ||
| unit |
| InterruptedException | ||
| IllegalStateException | if called after shutdown. |
References alma::acs::concurrent::ThreadLoopRunner::TaskWrapper::attemptCancelTask(), isDefunct, loop, runner, and taskWrapper.
Referenced by alma::acs::concurrent::ThreadLoopRunnerTest::testComplexWithSuspendAndRestart(), alma::acs::concurrent::ThreadLoopRunnerTest::testSetDelayTimeAndMode(), and alma::acs::concurrent::ThreadLoopRunnerTest::testSimple().
| synchronized void alma::acs::concurrent::ThreadLoopRunner::suspendLoop | ( | ) | [inline] |
Stops the loop, without attempting to cancel the possibly running action even if it was provided as a CancelableRunnable. Note also that this call returns quickly, without waiting for a possibly running action to finish.
The loop can be started again later via runLoop(). Suspending and restarting the loop does not lead to the creation of a new Thread.
| IllegalStateException | if called after shutdown. |
References isDefunct, and loop.
Referenced by suspendLoopAndWait(), and alma::acs::concurrent::ThreadLoopRunnerTest::testComplexWithSuspendAndRestart().
| synchronized boolean alma::acs::concurrent::ThreadLoopRunner::suspendLoopAndWait | ( | long | timeout, | |
| TimeUnit | unit | |||
| ) | throws InterruptedException [inline] |
Like suspendLoop(), but additionally waits for the currently running task (if any) to finish, with the given timeout applied.
If there is a task running and it fails to terminate, a subsequent call to runLoop() will fail with an IllegalStateException.
| timeout | ||
| unit |
| InterruptedException | if the calling thread is interrupted while waiting for the run method to finish. | |
| IllegalStateException | if called after shutdown. |
References alma::acs::concurrent::ThreadLoopRunner::TaskWrapper::awaitTaskFinish(), suspendLoop(), and taskWrapper.
Referenced by setDelayTime().
volatile ScheduleDelayMode alma::acs::concurrent::ThreadLoopRunner::delayMode [private] |
Referenced by getDelayMode(), runLoop(), and ThreadLoopRunner().
volatile long alma::acs::concurrent::ThreadLoopRunner::delayTimeNanos [private] |
Referenced by getDelayTimeMillis(), runLoop(), and setDelayTime().
final AtomicBoolean alma::acs::concurrent::ThreadLoopRunner::isDefunct [private] |
Referenced by isDisabled(), runLoop(), setDelayMode(), setDelayTime(), shutdown(), suspendLoop(), and ThreadLoopRunner().
final Logger alma::acs::concurrent::ThreadLoopRunner::logger [private] |
Referenced by setDelayTime().
volatile ScheduledFuture<?> alma::acs::concurrent::ThreadLoopRunner::loop [private] |
Referenced by isLoopRunning(), runLoop(), shutdown(), and suspendLoop().
final ScheduledExecutorService alma::acs::concurrent::ThreadLoopRunner::runner [private] |
Referenced by runLoop(), shutdown(), and ThreadLoopRunner().
final TaskWrapper alma::acs::concurrent::ThreadLoopRunner::taskWrapper [private] |
Referenced by isTaskRunning(), runLoop(), shutdown(), suspendLoopAndWait(), and ThreadLoopRunner().
1.6.2