Timer

What is Timer?

Timer is a tool used by threads to schedule tasks for future execution in background threads. Tasks can be scheduled for one-time execution or repeated periodically.
Corresponding to each Timer object is a separate background thread for sequentially executing tasks for all timers. The timer task should be completed soon. If a timer task takes too much time to complete, it will "occupy" the timer's task execution thread. Conversely, this may delay the execution of subsequent tasks that may "cluster" and execute quickly and continuously when (if) problematic tasks are finally completed.

  • This is because:

    The time for the first execution of a repetitive task, the time for the second execution, and the third... are well established.

    For example, if the first execution is 10:00:00 and it is executed every five seconds, the second execution is 10:00:05 and the third execution is 10:00:10. But if the first execution takes longer than 30s, the task executes directly as true when you make the following judgment. But we can not achieve the effect we need, that is, to execute the next task 5 seconds after each task is completed.

if (taskFired = (executionTime<=currentTime)) {
}

( Details are as follows:

     */
    private void mainLoop() {
        while (true) {
            try {
                TimerTask task;
                boolean taskFired;
                synchronized(queue) {
                    // Wait for queue to become non-empty
                    while (queue.isEmpty() && newTasksMayBeScheduled)
                        queue.wait();
                    if (queue.isEmpty())
                        break; // Queue is empty and will forever remain; die

                    // Queue nonempty; look at first evt and do the right thing
                    long currentTime, executionTime;
                    task = queue.getMin();
                    synchronized(task.lock) {
                        if (task.state == TimerTask.CANCELLED) {
                            queue.removeMin();
                            continue;  // No action required, poll queue again
                        }
                        currentTime = System.currentTimeMillis();
                        executionTime = task.nextExecutionTime;
                        if (taskFired = (executionTime<=currentTime)) {
                            if (task.period == 0) { // Non-repeating, remove
                                queue.removeMin();
                                task.state = TimerTask.EXECUTED;
                            } else { // Repeating task, reschedule
                                queue.rescheduleMin(
                                  task.period<0 ? currentTime   - task.period
                                                : executionTime + task.period);
                            }
                        }
                    }
                    if (!taskFired) // Task hasn't yet fired; wait
                        queue.wait(executionTime - currentTime);
                }
                if (taskFired)  // Task fired; run it, holding no locks
                    task.run();
            } catch(InterruptedException e) {
            }
        }

When the last real-time reference to the Timer object disappears and all unfinished tasks are completed, the task execution thread of the timer terminates normally (and becomes a garbage collection object). However, this may take any length of time to occur. By default, the task execution thread does not run as a daemon thread, so it prevents the application from terminating. If the caller wants to terminate the timer's task execution thread quickly, the caller should call the timer's cancel method.

If the timer's task execution thread terminates unexpectedly, for example, because its stop method is called, any further attempts to schedule tasks on the timer will result in IllegalStateException, as if the timer's cancel method had been called.

  • The reason is that the status of the scheduled task will be modified:
        synchronized(queue) {
            if (!thread.newTasksMayBeScheduled)
                throw new IllegalStateException("Timer already cancelled.");

            synchronized(task.lock) {
                if (task.state != TimerTask.VIRGIN)
                    throw new IllegalStateException(
                        "Task already scheduled or cancelled");
                task.nextExecutionTime = time;
                task.period = period;
                task.state = TimerTask.SCHEDULED;
            }

This class is thread-safe: multiple threads can share a single Timer object without external synchronization.

  • The reason is that both the operation of the task queue and the operation of a single task are locked.

Internally, it uses a binary heap to represent its task queue, so the cost of scheduling a task is O(log n), where n is the number of tasks that are scheduled concurrently.

This class does not provide real-time guarantees: it uses the Object.wait(long) method to schedule tasks.
Java 5.0 introduces the java.util.concurrent package, where one of the concurrent utilities is ScheduledThreadPoolExecutor, which is a thread pool for repeating tasks at a given rate or delay. It is actually a more generic alternative to the Timer / TimerTask combination because it allows multiple service threads, accepts various units of time, and does not require subclassifying TimerTasks (just implementing Runnable). Use a thread to configure ScheduledThreadPoolExecutor to be equivalent to Timer.
Implementing instructions: This type can be extended to a large number of concurrently scheduled tasks (thousands should be fine).

Key components in Timer
  • TimerThread

    Essentially, it is a thread whose purpose is to execute tasks (threads) in TaskQueue in a dead loop.

  • TaskQueue

    Essentially, it can be interpreted as a TimerTask array organized in a balanced binary tree data structure. (represented as a balanced binary tree)

  • TimerTask

    It is essentially a thread, but it contains other properties such as task status, task interval, next execution time, and so on.

Posted by mike_y on Wed, 24 Nov 2021 10:24:10 -0800