Network Security Internet Technology Development Database Servers Mobile Phone Android Software Apple Software Computer Software News IT Information

In addition to Weibo, there is also WeChat

Please pay attention

WeChat public account

Shulou

How to go deep into the implementation principle of Java Timer timing Task Scheduler

2025-02-23 Update From: SLTechnology News&Howtos shulou NAV: SLTechnology News&Howtos > Development >

Share

Shulou(Shulou.com)06/02 Report--

This article will explain in detail how to go deep into the implementation principle of the Java Timer timing task scheduler. The content of the article is of high quality, so the editor shares it for you as a reference. I hope you will have a certain understanding of the relevant knowledge after reading this article.

When using Java to schedule scheduled tasks, we often use the Timer class to do so. Timer is easy to use and its source code is very clear to read. In this section, let's take a closer look at the Timer class to see how the writers of the JDK source code implement a stable and reliable simple scheduler.

Timer usage

Timer scheduling tasks include one-time scheduling and round robin scheduling, which can be divided into fixed rate scheduling (fixRate) and fixed delay scheduling (fixDelay). A fixed rate is like working late today, but you have to go to work on time the next day. If you accidentally work overtime until 9: 00 the next morning, you won't even have time to rest. A fixed delay means that you have to sleep for eight hours before you come back to work, and if you work overtime until 6 o'clock in the morning, you can come to work in the afternoon. Fixed rate emphasizes punctuality, fixed delay emphasizes interval.

Timer timer = new Timer ()

TimerTask task = new TimerTask () {

Public void run () {

System.out.println ("wtf")

}

}

/ / delay 1 s to print wtf once

Timer.schedule (task, 1000)

/ / delay 1s fixed delay print wtf every 1s cycle

Timer.schedule (task, 1000, 1000)

/ / delay 1 s fixed rate printing wtf every 1 s cycle

Timer.scheduleAtFixRate (task, 1000, 1000)

If you have a task that must be scheduled on time every day, you should use a fixed rate schedule, and make sure that each task does not take too long to execute beyond the point of the next day. If you have a task that needs to be run every few minutes, use a fixed delay schedule, which doesn't really care how long your single task will run.

Internal structure

The Timer class contains a task queue and an asynchronous rotation thread. The task queue contains all the tasks to be executed, and all tasks will be executed in this asynchronous thread. Keep in mind that the execution code of the task should not throw an exception, otherwise it will cause the Timer thread to hang up and all tasks will not be executed. It is not easy to execute a single task for too long, otherwise it will affect the accuracy of task scheduling in time. For example, if you run one task for too long, the other tasks waiting to be scheduled have been in a state of hunger and cannot be scheduled. All tasks are executed by this single TimerThread thread.

Class Timer {

TaskQueue queue = new TaskQueue ()

TimerThread thread = new TimerThread (queue)

}

Timer's task queue TaskQueue is a special queue with an array inside. This array is sorted by heap time, and the top element of the heap is always the task with the least time to execute. The rotational training thread will perform the tasks that are closest in time and arrive at the time in each rotation. The array will automatically expand if there are a lot of tasks.

Class TaskQueue {

TimerTask [] queue = new TimerTask [128]

Int size

}

Any thread can add a task to TaskQueue through the Timer.schedule method, but TaskQueue is not a thread-safe data structure. It needs to be locked every time you modify the TaskQueue.

Synchronized (queue) {

...

}

Task status

TimerTask has four states, and VIRGIN is the default state, and the instantiation has not been scheduled. SCHEDULED indicates that the task has been crammed into the TaskQueue waiting to be executed. EXECUTED indicates that the task has been executed. CANCELLED said the task was canceled and was artificially canceled before it could be executed.

Abstract class TimerTask {

Int state = VIRGIN

Static final int VIRGIN = 0

Static final int SCHEDULED = 1

Static final int EXECUTED = 2

Static final int CANCELLED = 3

Long nextExecutionTime; / / next execution time

Long period = 0; / / interval

}

For a circular task, there is no EXECUTED state because it is rescheduled each time the execution is completed. The EXECUTED state exists only in an one-time task, and it doesn't really mean that the task has been executed, it means that it has been removed from the task queue and is about to be executed.

The task interval field period is special. When a fixed rate is used, the period is positive, when a fixed interval is used, the period is negative, and when the task is one-time, the period is zero. The following is the next scheduling time setting for the circular task

CurrentTime = System.currentTimeMillis ()

ExecutionTime = task.nextExecutionTime

/ / fixed delay is based on currentTime forward delay

/ / fixed rate based on executionTime (set time) smooth delay

/ / next_exec_time = exec_time + period = first_delay + n * period

Queue.rescheduleMin (

Task.period 0; iMurt -) {

If (queue.get (I). State = = TimerTask.CANCELLED) {

Queue.quickRemove (I)

Result++

}

}

}

/ / heap adjustment

If (result! = 0)

Queue.heapify ()

}

Return result

}

The task queue is empty.

There are no tasks in the task queue, and the scheduling thread must sleep according to a certain policy. It needs to sleep until the first task wakes up immediately, so the sleep deadline is the time when the first task will be executed. At the same time, new tasks may be added while sleeping, and its scheduling time may be earlier, so it is necessary to wake up the sleeping thread when a new task arrives.

Private void mainLoop () {

While (true) {

...

Task = queue.getMin ()

CurrentTime = System.currentTimeMillis ()

ExecutionTime = task.nextExecutionTime

If (executionTime > currentTime) {

/ / start to sleep.

Queue.wait (executionTime-currentTime)

}

...

}

}

/ / the new task is coming in.

Private void sched (TimerTask task, long time, long period) {

...

Queue.add (task)

If (queue.getMin () = = task)

Queue.notify (); / / Wake up the rotation thread

}

The wait () method in the code calls Object.wait () to sleep. When a new task comes in and finds that the running time of the new task is the earliest, call the notify () method to wake up the rotation thread.

Timer termination

Timer provides the cancel () method to clear the queue, stop the scheduler, and do not allow any new tasks to come in. It sets the newTasksMayBeScheduled field to false to indicate that Timer is about to terminate.

Class TimerThread {

...

Boolean newTasksMayBeScheduled; / / termination flag

...

}

Public void cancel () {

Synchronized (queue) {

Thread.newTasksMayBeScheduled = false

Queue.clear ()

Queue.notify ()

}

}

If the Timer is terminated, an exception will be thrown when a new task comes in.

Private void sched (TimerTask task, long time, long period) {

Synchronized (queue) {

If (! thread.newTasksMayBeScheduled)

Throw new IllegalStateException ("Timer already cancelled.")

...

}

}

We also notice that the Timer.cancel () method wakes up the rotation thread so that it can be stopped immediately. However, if the task is in progress, cancel () must wait until the task is finished before it can be stopped.

Private void mainLoop () {

While (true) {

/ / under normal emptying, the queue is empty and the training thread will sleep.

/ / but if newTasksMayBeScheduled is false

/ / then the loop will exit and the rotation thread will terminate.

While (queue.isEmpty () & & newTasksMayBeScheduled)

Queue.wait ()

If (queue.isEmpty ())

Break

...

}

}

Garbage collection

There is also a special scenario to pay special attention to, that is, when the training thread sleeps because there are no tasks in the queue, the Timer object is garbage collected because it is no longer referenced. At this time, you need to take the initiative to wake up the training thread and let it exit.

Class Timer {

...

Private final Object threadReaper = new Object () {

@ SuppressWarnings ("deprecation")

Protected void finalize () throws Throwable {

Synchronized (queue) {

Thread.newTasksMayBeScheduled = false

Queue.notify ()

}

}

}

...

}

When the Timer is recycled, the object pointed to by the internal field threadPeaper is also recycled. So the finalize method will be called to wake up and terminate the Timer rotation thread. Without this threadPeaper object, it is possible to leave zombie threads in the JVM.

On how to go deep into the Java Timer timing task scheduler implementation principle is shared here, I hope the above content can be of some help to you, can learn more knowledge. If you think the article is good, you can share it for more people to see.

Welcome to subscribe "Shulou Technology Information " to get latest news, interesting things and hot topics in the IT industry, and controls the hottest and latest Internet news, technology news and IT industry trends.

Views: 0

*The comments in the above article only represent the author's personal views and do not represent the views and positions of this website. If you have more insights, please feel free to contribute and share.

Share To

Development

Wechat

© 2024 shulou.com SLNews company. All rights reserved.

12
Report