JAVA随笔篇一(Timer源码分析和scheduleAtFixedRate的使用)

news/2024/7/7 16:46:01 标签: java, 定时器, Timer类, scheduleAtFixedRate

写完了基础篇,想了很久要不要去写进阶篇,去写JSP等等的使用方法,最后决定先不去写,因为自己并不是JAVA方面的大牛,目前也在边做边学,所以决定先将自己不懂的拿出来学并记下来。

Timer是Java自带的java.util.Timer类,通过调度一个java.util.TimerTask任务。这种方式可以让程序按照某一个频度执行。


1、Timer类的源码分析:

java">public class Timer {
    /**
     * The timer task queue.  This data structure is shared with the timer
     * thread.  The timer produces tasks, via its various schedule calls,
     * and the timer thread consumes, executing timer tasks as appropriate,
     * and removing them from the queue when they're obsolete.
     */
    private TaskQueue queue = new TaskQueue();

    /**
     * The timer thread.
     */
    private TimerThread thread = new TimerThread(queue);
首先Timer类定义了两个私有变量TaskQueue和TimerThread。

TaskQueue:Timer类定义了一个定时器任务队列,一个TimerTasks的优先级队列。

java">class TaskQueue {
    /**
     * Priority queue represented as a balanced binary heap: the two children
     * of queue[n] are queue[2*n] and queue[2*n+1].  The priority queue is
     * ordered on the nextExecutionTime field: The TimerTask with the lowest
     * nextExecutionTime is in queue[1] (assuming the queue is nonempty).  For
     * each node n in the heap, and each descendant of n, d,
     * n.nextExecutionTime <= d.nextExecutionTime.
     */
    private TimerTask[] queue = new TimerTask[128];

TimerThread:Timer类的任务执行线程,从Thread类继承。以TaskQueue为参数。

在使用Timer类,首先new一个Timer对象,然后利用scheduleXXX函数执行任务,首先分析Timer对象构造过程:

java">    public Timer() {
        this("Timer-" + serialNumber());
    }
java">    public Timer(boolean isDaemon) {
        this("Timer-" + serialNumber(), isDaemon);
    }<span style="white-space:pre">	</span>
java">    public Timer(String name) {
        thread.setName(name);
        thread.start();
    }
java">
    public Timer(String name, boolean isDaemon) {
        thread.setName(name);
        thread.setDaemon(isDaemon);
        thread.start();
    }
可以看出,Timer在构造对象过程中,需要启动一个TimerThread线程,因此可以猜测, TimerThread线程和Timer对象共同维护一个TaskQueue,利用TaskQueue进行信息传递。

接下来看scheduleXXX函数,所有的scheduleXXX函数都需要调用sched方法,

java">private void sched(TimerTask task, long time, long period) {
        if (time < 0)
            throw new IllegalArgumentException("Illegal execution time.");

        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;
            }

            queue.add(task);
            if (queue.getMin() == task)
                queue.notify();
        }
    }
这里首先介绍一下TimerTask类:

java">public abstract class TimerTask implements Runnable {
    /**
     * This object is used to control access to the TimerTask internals.
     */
    final Object lock = new Object();

TimerTask类实现了Runnable接口,待执行的任务置于run()中。在构造定时任务的时候,从TimerTask继承并实现run方法。并创建任务传给scheduleXXX方法。

sched方法中可以看出,sched方法中需要操作TaskQueue队列,而TimerThread线程启动之后同样使用这个队列,这就必须使用synchronized保证多线程安全使用。

2、scheduleXXX的使用:

Timer类的原理很简单,可以使用的函数不多,下面将全部列出。

(1)void java.util.Timer.schedule(TimerTask task, long delay):多长时间(毫秒)后执行任务

(2)void java.util.Timer.schedule(TimerTask task, Date time):设定某个时间执行任务

(3)void java.util.Timer.schedule(TimerTask task, long delay, long period):delay时间后开始执行任务,并每隔period时间调用任务一次。

(4)void java.util.Timer.schedule(TimerTask task, Date firstTime, long period):第一次在指定firstTime时间点执行任务,之后每隔period时间调用任务一次。

(5)void java.util.Timer.scheduleAtFixedRate(TimerTask task, long delay, long period):delay时间后开始执行任务,并每隔period时间调用任务一次。

(6)void java.util.Timer.scheduleAtFixedRate(TimerTask task, Date firstTime, long period):第一次在指定firstTime时间点执行任务,之后每隔period时间调用任务一次。

(7)void java.util.Timer.cancel():终止该Timer

(8)boolean java.util.TimerTask.cancel():终止该TimerTask

这些scheduleXXX方法中,除了(1)(2)外,其他都可以重复调用任务,主要的区别就是schedule和scheduleAtFixedRate的差别。


schedule()方法更注重保持间隔时间的稳定:保障每隔period时间可调用一次。


scheduleAtFixedRate()方法更注重保持执行频率的稳定:保障多次调用的频率趋近于period时间,如果某一次调用时间大于period,下一次就会尽量小于period,以保障频率接近于period


3、Timer类的使用示列

首先创建一个任务:

java"><pre name="code" class="java">import java.util.TimerTask;
public class MyTask extends TimerTask{
     private int id;
     public MyTask(int id){
         this.id = id;
     }
     public void run(){
         System.out.println("线程" + id + ":正在执行");
         //System.gc();
     }
}

 main函数代码: 

java">import java.util.Date;
import java.util.Timer;
public class Test{
    public static void main(String[] args){
        Timer timer = new Timer();
        timer.schedule(new MyTask(1), 5000);// 5秒后启动任务
        MyTask secondTask = new MyTask(2);
        timer.schedule(secondTask, 1000, 3000);
        // 1秒后启动任务,以后每隔3秒执行一次线程
        Date date = new Date();
        timer.schedule(new MyTask(3), new Date(date.getTime() + 1000));
        //      以date为参数,指定某个时间点执行线程
        //      timer.cancel();
        //      secondTask.cancel();
        System.out.println("main thread 结束!");
        }
}




http://www.niftyadmin.cn/n/1051249.html

相关文章

js中Number()、parseInt()和parseFloat()的区别

一&#xff1a;Number() 如果是Boolean值&#xff0c;true和false值将分别被转换为1和0。 如果是数字值&#xff0c;只是简单的传入和返回。 如果是null值&#xff0c;返回0。 如果是undefined&#xff0c;返回NaN。 如果是字符串&#xff1a; a. 如果字符串中只包含数字时&am…

equals==的使用

package stringyiwen; /* * :比较运算符&#xff0c;在基本数据类型比较的是值* &#xff1a;引用数据类型比较的是地址值 *//* * equals方法&#xff1a;【只】用于【引用数据数据类型】&#xff0c;如果对象没有继承Object类中的equals方法 * equals方法和 " "…

JAVA随笔篇二(深入分析JAVA简单类型、String和对象的值传递和引用传递)

关于JAVA的值传递和引用传递&#xff0c;翻看了很多资料和博客&#xff0c;感觉大多数讲的很乱&#xff0c;都是自己明白了之后就不讲了的样子&#xff0c;终于算是比较理解这几个概念了&#xff0c;下面做一个总结。 1、简单类型的参数传递 Java方法的参数是简单类型的时候&a…

Redis 和 I/O 多路复用

最近在看 UNIX 网络编程并研究了一下 Redis 的实现&#xff0c;感觉 Redis 的源代码十分适合阅读和分析&#xff0c;其中 I/O 多路复用&#xff08;mutiplexing&#xff09;部分的实现非常干净和优雅&#xff0c;在这里想对这部分的内容进行简单的整理。 几种 I/O 模型 为什么 …

Leetcode +160 Intersection of Two Linked Lists

Leetcode 160 Intersection of Two Linked Lists 题目描述 Write a program to find the node at which the intersection of two singly linked lists begins. For example, the following two linked lists: begin to intersect at node c1. Example 1: Input: intersect…

Maven项目初开发(一)Maven项目开发的初配置(1)

首先一个五脏俱全的eclipse是必须的&#xff0c;J2EE版的eclipse一般都是整合了Maven插件。 Maven缺省的本地仓库地址为${user.home}/.m2/repository 。也就是说&#xff0c;一个用户会对应的拥有一个本地仓库。当然你可以通过修改${user.home}/.m2/settings.xml 配置这个地址…

妮可妮可妮 [Hash]

妮可妮可妮 题目描述 小P特别喜欢动画Love Live中的角色妮可&#xff0c;每当他听到妮可说“niconiconi”时&#xff0c;他总会感到特别兴奋&#xff0c;还会露出绅士般的微笑。 作为一名理论计算机科学家&#xff0c;小P开始研究“niconiconi”这种串的特点。他发现&#xff0…

Leetcode +169 Majority Element

Leetcode 169 Majority Element 题目描述 Given an array of size n, find the majority element. The majority element is the element that appears more than ⌊ n/2 ⌋ times. You may assume that the array is non-empty and the majority element always exist in t…