Class NoThreadScheduler

  • All Implemented Interfaces:
    java.util.concurrent.Executor, PrioritySchedulerService, SchedulerService, SubmitterExecutor, SubmitterScheduler
    Direct Known Subclasses:
    NoThreadSchedulerStatisticTracker

    public class NoThreadScheduler
    extends AbstractPriorityScheduler
    Executor which has no threads itself. This allows you to have the same scheduler abilities (schedule tasks, recurring tasks, etc, etc), without having to deal with multiple threads, memory barriers, or other similar concerns. This class can be very useful in GUI development (if you want it to run on the GUI thread). It also can be useful in android development in a very similar way.

    The tasks in this scheduler are only progressed forward with calls to tick(ExceptionHandler). Since it is running on the calling thread, calls to Object.wait() and Thread.sleep() from sub tasks will block (possibly forever). The call to tick(ExceptionHandler) will not unblock till there is no more work for the scheduler to currently handle.

    Since:
    2.0.0
    • Constructor Detail

      • NoThreadScheduler

        public NoThreadScheduler()
        Constructs a new NoThreadScheduler scheduler.
      • NoThreadScheduler

        public NoThreadScheduler​(TaskPriority defaultPriority,
                                 long maxWaitForLowPriorityInMs)
        Constructs a new NoThreadScheduler scheduler with specified default priority behavior.
        Parameters:
        defaultPriority - Default priority for tasks which are submitted without any specified priority
        maxWaitForLowPriorityInMs - time low priority tasks to wait if there are high priority tasks ready to run
    • Method Detail

      • cancelTick

        public void cancelTick()
        Call to cancel current or the next tick call. If currently in a tick(ExceptionHandler) call (weather blocking waiting for tasks, or currently running tasks), this will call the tick(ExceptionHandler) to return. If a task is currently running it will finish the current task before returning. If not currently in a tick(ExceptionHandler) call, the next tick call will return immediately without running anything.
      • tick

        public int tick​(ExceptionHandler exceptionHandler)
        Invoking this will run any tasks which are ready to be run. This will block as it runs as many scheduled or waiting tasks as possible. It is CRITICAL that only one thread at a time calls the tick(ExceptionHandler) OR blockingTick(ExceptionHandler). While this class is in general thread safe, if multiple threads invoke either function at the same time, it is possible a given task may run more than once. In order to maintain high performance, threadly does not guard against this condition.

        This call allows you to specify an ExceptionHandler. If provided, if any tasks throw an exception, this will be called to communicate the exception. This allows you to ensure that you get a returned task count (meaning if provided, no exceptions will be thrown from this invocation). If null is provided for the exception handler, than any tasks which throw a RuntimeException, will throw out of this invocation.

        This call is NOT thread safe, calling tick(ExceptionHandler) or blockingTick(ExceptionHandler) in parallel could cause the same task to be run multiple times in parallel. Invoking in parallel will also make the behavior of getActiveTaskCount() non-deterministic and inaccurate.

        Parameters:
        exceptionHandler - Exception handler implementation to call if any tasks throw an exception, or null to have exceptions thrown out of this call
        Returns:
        quantity of tasks run during this tick invocation
        Since:
        3.2.0
      • blockingTick

        public int blockingTick​(ExceptionHandler exceptionHandler)
                         throws java.lang.InterruptedException
        This is similar to tick(ExceptionHandler), except that it will block until there are tasks ready to run, or until cancelTick() is invoked.

        Once there are tasks ready to run, this will continue to block as it runs as many tasks that are ready to run.

        It is CRITICAL that only one thread at a time calls the tick(ExceptionHandler) OR blockingTick(ExceptionHandler).

        This call allows you to specify an ExceptionHandler. If provided, if any tasks throw an exception, this will be called to communicate the exception. This allows you to ensure that you get a returned task count (meaning if provided, no exceptions will be thrown from this invocation). If null is provided for the exception handler, than any tasks which throw a RuntimeException, will throw out of this invocation.

        This call is NOT thread safe, calling tick(ExceptionHandler) or blockingTick(ExceptionHandler) in parallel could cause the same task to be run multiple times in parallel. Invoking in parallel will also make the behavior of getActiveTaskCount() non-deterministic and inaccurate.

        Parameters:
        exceptionHandler - Exception handler implementation to call if any tasks throw an exception, or null to have exceptions thrown out of this call
        Returns:
        quantity of tasks run during this tick invocation
        Throws:
        java.lang.InterruptedException - thrown if thread is interrupted waiting for task to run
        Since:
        4.0.0
      • scheduleWithFixedDelay

        public void scheduleWithFixedDelay​(java.lang.Runnable task,
                                           long initialDelay,
                                           long recurringDelay,
                                           TaskPriority priority)
        Description copied from interface: PrioritySchedulerService
        Schedule a fixed delay recurring task to run. The recurring delay time will be from the point where execution has finished. So the execution frequency is the recurringDelay + runtime for the provided task.

        Unlike ScheduledExecutorService if the task throws an exception, subsequent executions are NOT suppressed or prevented. So if the task throws an exception on every run, the task will continue to be executed at the provided recurring delay (possibly throwing an exception on each execution).

        Parameters:
        task - runnable to be executed
        initialDelay - delay in milliseconds until first run
        recurringDelay - delay in milliseconds for running task after last finish
        priority - priority for task to get available thread to run on
      • scheduleAtFixedRate

        public void scheduleAtFixedRate​(java.lang.Runnable task,
                                        long initialDelay,
                                        long period,
                                        TaskPriority priority)
        Description copied from interface: PrioritySchedulerService
        Schedule a fixed rate recurring task to run. The recurring delay will be the same, regardless of how long task execution takes. A given runnable will not run concurrently (unless it is submitted to the scheduler multiple times). Instead of execution takes longer than the period, the next run will occur immediately (given thread availability in the pool).

        Unlike ScheduledExecutorService if the task throws an exception, subsequent executions are NOT suppressed or prevented. So if the task throws an exception on every run, the task will continue to be executed at the provided recurring delay (possibly throwing an exception on each execution).

        Parameters:
        task - runnable to be executed
        initialDelay - delay in milliseconds until first run
        period - amount of time in milliseconds between the start of recurring executions
        priority - priority for task to get available thread to run on
      • getActiveTaskCount

        public int getActiveTaskCount()
        Description copied from interface: SchedulerService
        Call to check how many tasks are currently being executed in this scheduler.
        Returns:
        current number of running tasks
      • isShutdown

        public boolean isShutdown()
        Description copied from interface: SchedulerService
        Function to check if the thread pool is currently accepting and handling tasks.
        Returns:
        true if thread pool is running
      • hasTaskReadyToRun

        public boolean hasTaskReadyToRun()
        Checks if there are tasks ready to be run on the scheduler. Generally this is called from the same thread that would call tick(ExceptionHandler) (but does not have to be). If tick(ExceptionHandler) is not currently being called, this call indicates if the next tick(ExceptionHandler) will have at least one task to run. If tick(ExceptionHandler) is currently being invoked, this call will do a best attempt to indicate if there is at least one more task to run (not including the task which may currently be running). It's a best attempt as it will try not to block the thread invoking tick(ExceptionHandler) to prevent it from accepting additional work.
        Returns:
        true if there are task waiting to run
      • getDelayTillNextTask

        public long getDelayTillNextTask()
        Checks how long till the next task will be ready to execute. If there are no tasks in this scheduler currently then Long.MAX_VALUE will be returned. If there is a task ready to execute this will return a value less than or equal to zero. If the task is past its desired point of execution the result will be a negative amount of milliseconds past that point in time.

        Generally this is called from the same thread that would invoke tick(ExceptionHandler) (but does not have to be). Since this does not block or lock if being invoked in parallel with tick(ExceptionHandler), the results may be no longer accurate by the time this invocation has returned.

        If a recurring task is currently running this will return a very large number. This will remain until the task has rescheduled itself. To avoid this just ensure this is never invoked in parallel with tick(ExceptionHandler).

        This can be useful if you want to know how long you can block on something, ASSUMING you can detect that something has been added to the scheduler, and interrupt that blocking in order to handle tasks.

        Returns:
        Milliseconds till the next task is ready to run
      • clearTasks

        public java.util.List<java.lang.Runnable> clearTasks()
        Removes any tasks waiting to be run. Will not interrupt any tasks currently running if tick(ExceptionHandler) is being called. But will avoid additional tasks from being run on the current tick(ExceptionHandler) call.

        If tasks are added concurrently during this invocation they may or may not be removed.

        Returns:
        List of runnables which were waiting in the task queue to be executed (and were now removed)