All Downloads are FREE. Search and download functionalities are using the official Maven repository.

Alachisoft.NCache.Common.Threading.TimeScheduler Maven / Gradle / Ivy

package Alachisoft.NCache.Common.Threading;

import Alachisoft.NCache.Common.Logger.ILogger;

/**
 * The scheduler supports varying scheduling intervals by asking the task every time for its next preferred scheduling interval. Scheduling can either be fixed-delay or
 * fixed-rate. In fixed-delay scheduling, the task's new schedule is calculated as:

new_schedule = time_task_starts + scheduling_interval

In fixed-rate * scheduling, the next schedule is calculated as:

new_schedule = time_task_was_supposed_to_start + scheduling_interval

The scheduler internally holds a queue of * tasks sorted in ascending order according to their next execution time. A task is removed from the queue if it is cancelled, i.e. if TimeScheduler.Task.isCancelled() * returns true.

Initially, the scheduler is in SUSPENDed mode, start() need not be called: if a task is added, the scheduler gets started automatically. * Calling start() starts the scheduler if it's suspended or stopped else has no effect. Once stop() is called, added tasks will not restart it: start() * has to be called to restart the scheduler.

*

*

* Fixed-delay and fixed-rate single thread scheduler

Author: Chris Koiak, Bela Ban

Date: 12/03/2003

*/ public class TimeScheduler implements Runnable { /** * Needed in case all tasks have been cancelled and we are still waiting on the schedule time of the task at the top *

* Regular wake-up intervals for scheduler */ private static final long TICK_INTERVAL = 1000; /** * TimeScheduler thread name */ private static final String THREAD_NAME = "TimeScheduler.Thread"; private static ILogger _logger = null; /** * The scheduler thread */ private Thread thread = null; /** * The thread's running state */ private State thread_state = State.SUSPEND; /** * Time that task queue is empty before suspending the scheduling thread */ private long suspend_interval; /** * Sorted list of * IntTasks */ private EventQueue queue; /** * Create a scheduler that executes tasks in dynamically adjustable intervals * * @param suspend_interval The time that the scheduler will wait for at least one task to be placed in the task queue before suspending the scheduling thread */ public TimeScheduler(long suspend_interval) { queue = new EventQueue(); this.suspend_interval = suspend_interval; } /** * Create a scheduler that executes tasks in dynamically adjustable intervals */ public TimeScheduler() { this(2000); } /** * Set the thread state to running, create and start the thread */ private void _start() { synchronized (this) { if (thread_state != State.DISPOSED) { thread_state = State.RUN; thread = new Thread(this); thread.setName(THREAD_NAME); thread.setDaemon(true); thread.start(); } } } /** * Restart the suspended thread */ private void _unsuspend() { _start(); } /** * Set the thread state to suspended */ private void _suspend() { synchronized (this) { if (thread_state != State.DISPOSED) { thread_state = State.SUSPEND; thread = null; } } } /** * Set the thread state to stopping */ private void _stopping() { synchronized (this) { if (thread_state != State.DISPOSED) { thread_state = State.STOPPING; } } } /** * Set the thread state to stopped */ private void _stop() { synchronized (this) { if (thread_state != State.DISPOSED) { thread_state = State.STOP; thread = null; } } } /** * Get the first task, if the running time hasn't been reached then wait a bit and retry. Else reschedule the task and then run it. * *

* If the task queue is empty, sleep until a task comes in or if slept for too long, suspend the thread. */ @Override public void run() { long elapsedTime; try { while (true) { synchronized (this) { if (thread == null) { return; } } Task task = null; boolean lockReAcquired = true; synchronized (queue) { if (queue.getIsEmpty()) { //Monitor.Wait(queue, (int) suspend_interval); long startTime = System.nanoTime(); Monitor.wait(queue); //queue.wait(); long endTime = System.nanoTime(); lockReAcquired = (endTime - startTime) < suspend_interval; } // if (queue.getIsEmpty()) // { // _suspend(); // return; // } if (lockReAcquired) { QueuedEvent e = queue.Peek(); if (e != null) { synchronized (e) { task = e.Task; if (task.IsCancelled()) { queue.Pop(); continue; } elapsedTime = e.getElapsedTime(); if (elapsedTime >= e.getInterval()) { // Reschedule the task queue.Pop(); if (e.ReQueue()) { queue.Push(e); } } } if (elapsedTime < e.getInterval()) { //Monitor.Wait(queue, (int) (e.getInterval() - elapsedTime)); Monitor.wait(queue, e.getInterval() - elapsedTime);// queue.wait((e.getInterval() - elapsedTime)); continue; } } } } synchronized (this) { if (queue.getIsEmpty() && !lockReAcquired) { _suspend(); return; } } try { if (task != null) { task.Run(); } } catch (Exception ex) { //System.err.println("TimeScheduler._run() " + ex.getMessage()); // _logger.Error("TimeScheduler._run()", ex.toString()); } } } catch (InterruptedException ex) { //System.err.println("TimeScheduler._run() " + ex.getMessage()); // _logger.Error("TimeScheduler._run()", ex.getMessage()); } } /** * Relative Scheduling true:

Task is rescheduled relative to the last time it actually started execution

false:

Task is * scheduled relative to its last execution schedule. This has the effect that the time between two consecutive executions of the task remains the same.

*

*

* Add a task for execution at adjustable intervals * * @param t The task to execute * @param relative Use relative scheduling */ public final void AddTask(Task t, boolean relative) { long interval; synchronized (this) { if (thread_state == State.DISPOSED) { return; } if ((interval = t.GetNextInterval()) < 0) { return; } queue.Push(new QueuedEvent(t)); switch (thread_state) { case RUN: //Monitor.PulseAll(queue); break; case SUSPEND: _unsuspend(); break; case STOPPING: break; case STOP: break; } } } /** * Add a task for execution at adjustable intervals * * @param t The task to execute */ public final void AddTask(Task t) { AddTask(t, true); } /** * Start the scheduler, if it's suspended or stopped */ public final void Start() { synchronized (this) { switch (thread_state) { case DISPOSED: break; case RUN: break; case SUSPEND: _unsuspend(); break; case STOPPING: break; case STOP: _start(); break; } } } /** * Stop the scheduler if it's running. Switch to stopped, if it's suspended. Clear the task queue. */ public final void Stop() throws InterruptedException { // i. Switch to STOPPING, interrupt thread // ii. Wait until thread ends // iii. Clear the task queue, switch to STOPPED, synchronized (this) { switch (thread_state) { case RUN: _stopping(); break; case SUSPEND: _stop(); return; case STOPPING: return; case STOP: return; case DISPOSED: return; } thread.interrupt(); } thread.join(); synchronized (this) { queue.Clear(); _stop(); } } /** * Performs application-defined tasks associated with freeing, releasing, or resetting unmanaged resources. */ public void dispose() throws InterruptedException { Thread tmp = null; synchronized (this) { if (thread_state == State.DISPOSED) { return; } tmp = thread; thread_state = State.DISPOSED; thread = null; if (tmp != null) { tmp.interrupt(); } } if (tmp != null) { tmp.join(); //for (int i = 0; i < queue.Count; i++) //{ // IDisposable disposable = queue.Pop().Task as IDisposable; // disposable.Dispose(); //} queue.Clear(); } } private enum State { /** * State Constant */ RUN(0), /** * State Constant */ SUSPEND(1), /** * State Constant */ STOPPING(2), /** * State Constant */ STOP(3), /** * State Constant */ DISPOSED(4); private static java.util.HashMap mappings; private int intValue; private State(int value) { intValue = value; State.getMappings().put(value, this); } private static java.util.HashMap getMappings() { if (mappings == null) { synchronized (State.class) { if (mappings == null) { mappings = new java.util.HashMap(); } } } return mappings; } public static State forValue(int value) { return getMappings().get(value); } public int getValue() { return intValue; } } /** * The interface that submitted tasks must implement */ public interface Task { /** * Returns true if task is cancelled and shouldn't be scheduled again * * @return */ boolean IsCancelled(); /** * The next schedule interval * * @return The next schedule interval */ long GetNextInterval(); /** * Execute the task */ void Run(); } }





© 2015 - 2025 Weber Informatics LLC | Privacy Policy