timer定时器用法_定时器怎么调时间

timer定时器用法_定时器怎么调时间在JDK类库中Timer类主要负责计划任务的功能,也就是在指定的时间开始执行某一个任务。此类也常用来做一下周期性同步工作,代替它的有quartz、SpringTask。Timer类的主要作用是设置计划

大家好,又见面了,我是你们的朋友全栈君。如果您正在找激活码,请点击查看最新教程,关注关注公众号 “全栈程序员社区” 获取激活教程,可能之前旧版本教程已经失效.最新Idea2022.1教程亲测有效,一键激活。

Jetbrains全系列IDE使用 1年只要46元 售后保障 童叟无欺

  在JDK类库中Timer类主要负责计划任务的功能,也就是在指定的时间开始执行某一个任务。此类也常用来做一下周期性同步工作,代替它的有quartz、SpringTask。Timer类的主要作用是设置计划任务,但封装任务的类是TimerTask类(实际该类是一个抽象类,执行任务的代码要放在该类的子类中)。Timer类的主要方法列表如下:

构造方法

timer定时器用法_定时器怎么调时间

 

成员方法:

timer定时器用法_定时器怎么调时间

 

Timer内部维护一个  TimerThread   线程,而且线程名字与Thread类一样,默认用一个静态成员变量进行生成全局序列。

public class Timer {

    private final TaskQueue queue = new TaskQueue();

    /**
     * The timer thread.
     */
    private final TimerThread thread = new TimerThread(queue);

    /**
     * This ID is used to generate thread names.
     */
    private final static AtomicInteger nextSerialNumber = new AtomicInteger(0);

 

TimerThread的run方法中while循环获取TaskQueue中的task并且执行任务(mainLoop中执行执行task.run()方法–相当于同步调用)

class TimerThread extends Thread {
 
    boolean newTasksMayBeScheduled = true;

    private TaskQueue queue;

    TimerThread(TaskQueue queue) {
        this.queue = queue;
    }

    public void run() {
        try {
            mainLoop();
        } finally {
            synchronized(queue) {
                newTasksMayBeScheduled = false;
                queue.clear();  // Eliminate obsolete references
            }
        }
    }

    /**
     * The main timer loop.  (See class comment.)
     */
    private void mainLoop() {
        while (true) {
      。。。。。。
        }
    }

 

 TaskQueue用于存放TimerTask任务(内部维护一个TimerTask数组)。

class TaskQueue {

    private TimerTask[] queue = new TimerTask[128];

  。。。

 

TimerTask是一个继承Runnable接口的抽象类:

public abstract class TimerTask implements Runnable {

    final Object lock = new Object();
。。。

TimerTask有一个cancel方法用于将当前任务从任务队列删除。(也就是队列中不会执行该任务,如果正在执行中调用该方法会执行完毕)

    public boolean cancel() {
        synchronized(lock) {
            boolean result = (state == SCHEDULED);
            state = CANCELLED;
            return result;
        }
    }

 

 1. Sschedule(task, Date)的用法

  此方法用于在指定的时间执行一次task。默认的执行完毕不会结束线程,因为timer的成员属性thread默认是非守护线程,而且其run方法中通过轮询同步调用task的run()方法。

例子1:一个简单的测试:(在未来时间执行一次任务—会到指定之间执行run()方法)

package cn.qlq.thread.fourteen;

import java.util.Date;
import java.util.Timer;
import java.util.TimerTask;

import org.slf4j.Logger;
import org.slf4j.LoggerFactory;

public class Demo1 extends TimerTask {
    private static final Logger LOGGER = LoggerFactory.getLogger(Demo1.class);

    public static void main(String[] args) throws InterruptedException {
        LOGGER.info("start ");
        Timer timer = new Timer();
        Demo1 task = new Demo1();
        Date runtime = new Date(System.currentTimeMillis() + 5000);
        timer.schedule(task, runtime);
        LOGGER.info("end ");
    }

    @Override
    public void run() {
        for (int i = 0; i < 5; i++) {
            LOGGER.info("threadName -> {},value -> {}", Thread.currentThread().getName(), i + "");
            try {
                Thread.sleep(1 * 1000);
            } catch (InterruptedException e) {
                e.printStackTrace();
            }
        }
    }
}

结果:(可以看到先打印的end,后执行的run中方法,并且执行完毕之后进程并未销毁。也验证了是新开一个线程进行操作,并且线程是非守护线程)

timer定时器用法_定时器怎么调时间

 

 查看源码:

    public Timer() {
        this("Timer-" + serialNumber());
    }
    public Timer(String name) {
        thread.setName(name);
        thread.start();
    }

 

 如果将上面Timer中的TimerThread设为守护线程将不会执行run中方法,因为main线程执行完毕,没有非守护线程的存在,所以守护线程也销毁导致进程销毁。

另一种办法是等待执行完之后调用timer.cancel()

    public static void main(String[] args) throws InterruptedException {
        LOGGER.info("start ");
        Timer timer = new Timer();
        Demo1 task = new Demo1();
        Date runtime = new Date(System.currentTimeMillis() + 5000);
        timer.schedule(task, runtime);
        LOGGER.info("end ");
        
        Thread.sleep(6*1000);
        timer.cancel();
    }

结果:

timer定时器用法_定时器怎么调时间

 

 例子2:多个任务在之前的时间执行—(线性顺序执行多个task,是从queue中获取task然后执行,如果时间早于当前时间会马上执行任务)

package cn.qlq.thread.fourteen;

import java.util.Date;
import java.util.Timer;
import java.util.TimerTask;

import org.slf4j.Logger;
import org.slf4j.LoggerFactory;

public class Demo1 extends TimerTask {
    private static final Logger LOGGER = LoggerFactory.getLogger(Demo1.class);
    private String name;

    public static void main(String[] args) throws InterruptedException {
        LOGGER.info("start ");
        Timer timer = new Timer();
        Demo1 task = new Demo1("t1");
        Demo1 task2 = new Demo1("t2");
        Date runtime = new Date(System.currentTimeMillis() - 5000);
        timer.schedule(task, runtime);
        timer.schedule(task2, runtime);
        LOGGER.info("end ");
    }

    @Override
    public void run() {
        for (int i = 0; i < 5; i++) {
            LOGGER.info("threadName -> {},value -> {},taskName->{}", Thread.currentThread().getName(), i + "", name);
            try {
                Thread.sleep(1 * 1000);
            } catch (InterruptedException e) {
                e.printStackTrace();
            }
        }
    }

    public String getName() {
        return name;
    }

    public void setName(String name) {
        this.name = name;
    }

    public Demo1(String name) {
        super();
        this.name = name;
    }
}

结果:

timer定时器用法_定时器怎么调时间

 2. Sschedule(TimerTask task, Date firsttime,long period)的用法

   此方法用于在指定的时间执行一次之后任务之后,在指定的period的时间间隔后不停的执行任务

package cn.qlq.thread.fourteen;

import java.util.Date;
import java.util.Timer;
import java.util.TimerTask;

import org.slf4j.Logger;
import org.slf4j.LoggerFactory;

public class Demo2 extends TimerTask {
    private static final Logger LOGGER = LoggerFactory.getLogger(Demo2.class);
    private String name;

    public static void main(String[] args) throws InterruptedException {
        LOGGER.info("start ");
        Timer timer = new Timer();
        Demo2 task = new Demo2("t1");
        Demo2 task2 = new Demo2("t2");
        Date runtime = new Date(System.currentTimeMillis() + 5000);
        timer.schedule(task, runtime, 20 * 1000);
        timer.schedule(task2, runtime, 20 * 1000);
        LOGGER.info("end ");
    }

    @Override
    public void run() {
        for (int i = 0; i < 5; i++) {
            LOGGER.info("threadName -> {},value -> {},taskName->{}", Thread.currentThread().getName(), i + "", name);
            try {
                Thread.sleep(1 * 1000);
            } catch (InterruptedException e) {
                e.printStackTrace();
            }
        }
    }

    public String getName() {
        return name;
    }

    public void setName(String name) {
        this.name = name;
    }

    public Demo2(String name) {
        super();
        this.name = name;
    }
}

结果:(时间间隔是从任务开始执行计算的,也就是从当前任务执行的开始时间到下次任务开始时间的间隔是20秒)

timer定时器用法_定时器怎么调时间

 3. Shedule(TimerTask task, long delay)的用法

   以当前时间为参考,在延迟指定的秒数后执行一次性任务;如果延迟时间是负数会抛出IllegalArgumentException异常。

package cn.qlq.thread.fourteen;

import java.util.Timer;
import java.util.TimerTask;

import org.slf4j.Logger;
import org.slf4j.LoggerFactory;

public class Demo3 extends TimerTask {
    private static final Logger LOGGER = LoggerFactory.getLogger(Demo3.class);
    private String name;

    public static void main(String[] args) throws InterruptedException {
        LOGGER.info("start ");
        Timer timer = new Timer();
        Demo3 task = new Demo3("t1");
        timer.schedule(task, 2 * 1000);
        LOGGER.info("end ");
    }

    @Override
    public void run() {
        for (int i = 0; i < 5; i++) {
            LOGGER.info("threadName -> {},value -> {},taskName->{}", Thread.currentThread().getName(), i + "", name);try {
                Thread.sleep(1 * 1000);
            } catch (InterruptedException e) {
                e.printStackTrace();
            }
        }
    }

    public String getName() {
        return name;
    }

    public void setName(String name) {
        this.name = name;
    }

    public Demo3(String name) {
        super();
        this.name = name;
    }
}

 结果:(执行完线程不会关闭)

timer定时器用法_定时器怎么调时间

 4. Shedule(TimerTask task, long delay,long period)的用法

   以当前时间为参考,在延迟指定的秒数后第一次执行任务;如果延迟时间是负数会抛出IllegalArgumentException异常。并且在period后重复执行任务,执行时间是从上次任务结束时间开始计算。凡是带period的都会在时间间隔后重复执行。

package cn.qlq.thread.fourteen;

import java.util.Timer;
import java.util.TimerTask;

import org.slf4j.Logger;
import org.slf4j.LoggerFactory;

public class Demo4 extends TimerTask {
    private static final Logger LOGGER = LoggerFactory.getLogger(Demo4.class);
    private String name;

    public static void main(String[] args) throws InterruptedException {
        LOGGER.info("start ");
        Timer timer = new Timer();
        Demo4 task = new Demo4("t1");
        timer.schedule(task, 2 * 1000, 10 * 1000);
        LOGGER.info("end ");
    }

    @Override
    public void run() {
        for (int i = 0; i < 5; i++) {
            LOGGER.info("threadName -> {},value -> {},taskName->{}", Thread.currentThread().getName(), i + "", name);
            try {
                Thread.sleep(1 * 1000);
            } catch (InterruptedException e) {
                e.printStackTrace();
            }
        }
    }

    public String getName() {
        return name;
    }

    public void setName(String name) {
        this.name = name;
    }

    public Demo4(String name) {
        super();
        this.name = name;
    }
}

结果

timer定时器用法_定时器怎么调时间

 

 5. sheduleAtFixedRate(TimerTask task, Date firstTime,long period)的用法

   方法schedule和scheduleAtFixedRate都会按顺序执行,所以不要考虑非线程安全的情况。

  在有延时和没有延时的情况下,周期性的任务的下次任务开始时间都是相对于上次任务的开始时间进行延迟(这个在并发编程书中说的是有延迟的情况下相对于结束时间,但是自己测的是相对于开始时间)

  schedule和scheduleAtFixedRate的区别在于,如果指定开始执行的时间在当前系统运行时间之前,scheduleAtFixedRate会把已经过去的时间也作为周期执行,而schedule不会把过去的时间算上

1.scheduleAtFixedRate(TimerTask task,long delay,long period)   有延迟,下次任务相对于上次任务的开始时间开始执行:

package cn.qlq.thread.fourteen;

import java.util.Timer;
import java.util.TimerTask;

import org.slf4j.Logger;
import org.slf4j.LoggerFactory;

public class Demo5 extends TimerTask {
    private static final Logger LOGGER = LoggerFactory.getLogger(Demo5.class);
    private String name;

    public static void main(String[] args) throws InterruptedException {
        LOGGER.info("start ");
        Timer timer = new Timer();
        Demo5 task = new Demo5("t1");
        timer.scheduleAtFixedRate(task, 2 * 1000, 10 * 1000);
        LOGGER.info("end ");
    }

    @Override
    public void run() {
        for (int i = 0; i < 5; i++) {
            LOGGER.info("threadName -> {},value -> {},taskName->{}", Thread.currentThread().getName(), i + "", name);
            try {
                Thread.sleep(1 * 1000);
            } catch (InterruptedException e) {
                e.printStackTrace();
            }
        }
    }

    public String getName() {
        return name;
    }

    public void setName(String name) {
        this.name = name;
    }

    public Demo5(String name) {
        super();
        this.name = name;
    }
}

结果:

timer定时器用法_定时器怎么调时间

 

2.scheduleAtFixedRate(TimerTask task,Date startTime,long period)   指定开始执行的时间在当前系统运行时间之前,会把已经过去的时间也作为周期执行

package cn.qlq.thread.fourteen;

import java.util.Date;
import java.util.Timer;
import java.util.TimerTask;

import org.slf4j.Logger;
import org.slf4j.LoggerFactory;

public class Demo6 extends TimerTask {
    private static final Logger LOGGER = LoggerFactory.getLogger(Demo6.class);
    private String name;

    public static void main(String[] args) throws InterruptedException {
        LOGGER.info("start ");
        Timer timer = new Timer();
        Demo6 task = new Demo6("t1");
        timer.scheduleAtFixedRate(task, new Date(System.currentTimeMillis() - 5000), 10 * 1000);
        LOGGER.info("end ");
    }

    @Override
    public void run() {
        for (int i = 0; i < 3; i++) {
            LOGGER.info("threadName -> {},value -> {},taskName->{}", Thread.currentThread().getName(), i + "", name);
            try {
                Thread.sleep(1 * 1000);
            } catch (InterruptedException e) {
                e.printStackTrace();
            }
        }
    }

    public String getName() {
        return name;
    }

    public void setName(String name) {
        this.name = name;
    }

    public Demo6(String name) {
        super();
        this.name = name;
    }
}

结果:(第二次任务把之前的5秒钟也包含在延迟时间内)

timer定时器用法_定时器怎么调时间

 

补充:

1.TimerTask有一个cancel方法用于将当前任务从任务队列删除。(也就是队列中不会执行该任务,如果正在执行中调用该方法会执行完毕)

package cn.qlq.thread.fourteen;

import java.util.Date;
import java.util.Timer;
import java.util.TimerTask;

import org.slf4j.Logger;
import org.slf4j.LoggerFactory;

public class Demo2 extends TimerTask {
    private static final Logger LOGGER = LoggerFactory.getLogger(Demo2.class);
    private String name;

    public static void main(String[] args) throws InterruptedException {
        LOGGER.info("start ");
        Timer timer = new Timer();
        Demo2 task = new Demo2("t1");
        Demo2 task2 = new Demo2("t2");
        Date runtime = new Date(System.currentTimeMillis() + 5000);
        timer.schedule(task, runtime, 20 * 1000);
        timer.schedule(task2, runtime, 20 * 1000);
        LOGGER.info("end ");
    }

    @Override
    public void run() {
        for (int i = 0; i < 5; i++) {
            LOGGER.info("threadName -> {},value -> {},taskName->{}", Thread.currentThread().getName(), i + "", name);
            if (name.equals("t1")) {
                this.cancel();
            }
            try {
                Thread.sleep(1 * 1000);
            } catch (InterruptedException e) {
                e.printStackTrace();
            }
        }
    }

    public String getName() {
        return name;
    }

    public void setName(String name) {
        this.name = name;
    }

    public Demo2(String name) {
        super();
        this.name = name;
    }
}

结果:(t1任务被删除)

timer定时器用法_定时器怎么调时间

 

 2.Timer的cancel方法用于清空所有任务队列(如果有任务正在执行会等任务执行完清空;有时候不一定会停掉,因为cancel方法不一定能抢到queue对象的锁)

package cn.qlq.thread.fourteen;

import java.util.Date;
import java.util.Timer;
import java.util.TimerTask;

import org.slf4j.Logger;
import org.slf4j.LoggerFactory;

public class Demo2 extends TimerTask {
    private static final Logger LOGGER = LoggerFactory.getLogger(Demo2.class);
    private String name;

    public static void main(String[] args) throws InterruptedException {
        LOGGER.info("start ");
        Timer timer = new Timer();
        Demo2 task = new Demo2("t1");
        Demo2 task2 = new Demo2("t2");
        Date runtime = new Date(System.currentTimeMillis());
        timer.schedule(task, runtime, 20 * 1000);
        timer.schedule(task2, runtime, 20 * 1000);
        LOGGER.info("end ");
        Thread.sleep(2 * 1000);
        timer.cancel();
        LOGGER.info("timer cancel");
    }

    @Override
    public void run() {
        for (int i = 0; i < 5; i++) {
            LOGGER.info("threadName -> {},value -> {},taskName->{}", Thread.currentThread().getName(), i + "", name);
            if (name.equals("t1")) {
                this.cancel();
            }
            try {
                Thread.sleep(1 * 1000);
            } catch (InterruptedException e) {
                e.printStackTrace();
            }
        }
    }

    public String getName() {
        return name;
    }

    public void setName(String name) {
        this.name = name;
    }

    public Demo2(String name) {
        super();
        this.name = name;
    }
}

结果:

timer定时器用法_定时器怎么调时间

 

版权声明:本文内容由互联网用户自发贡献,该文观点仅代表作者本人。本站仅提供信息存储空间服务,不拥有所有权,不承担相关法律责任。如发现本站有涉嫌侵权/违法违规的内容, 请联系我们举报,一经查实,本站将立刻删除。

发布者:全栈程序员-站长,转载请注明出处:https://javaforall.net/168301.html原文链接:https://javaforall.net

(0)
全栈程序员-站长的头像全栈程序员-站长


相关推荐

  • Actuator「建议收藏」

    Actuator「建议收藏」#Actuator引入依赖spring-boot-starter-actuator,通过endpoint来暴露HTTP或JMX来监管应用通过http://localhost:8080/actuat

    2022年8月5日
    2
  • MVC三层架构(详解)「建议收藏」

    MVC三层架构(详解)「建议收藏」1:初始MVC(1):三层架构三层架构是指:视图层View、服务层Service,与持久层Dao。它们分别完成不同的功能。View层:用于接收用户提交请求的代码在这里编写。Service层:系统的业务逻辑主要在这里完成。Dao层:直接操作数据库的代码在这里编写。为了更好的降低各层间的耦合度,在三层架构程序设计中,采用面向抽象编程。即上层对下层的调用,是通过接口实现的。而下层对上层的真正服务提供者,是下层接口的实现类。服务标准(接口)是相同的,服务提供者(实现类)可以更换。这就

    2022年6月25日
    23
  • android 画图 平面图,房屋平面图 DIY 神工具!「MagicPlan」用手机拍照就自动帮你画好(iPhone, Android)…

    android 画图 平面图,房屋平面图 DIY 神工具!「MagicPlan」用手机拍照就自动帮你画好(iPhone, Android)…不论是新屋装潢还是老屋改装,为了省下设计费,许多人都会想自己动手画平面图,但是如果本身没有相关的底子,从怎么开始动手测量尺寸到画出完整的全屋平面图,每个点都有让人不知所措的地方。来!免惊~「MagicPlan」快拿去用!它简直就是我们这种无设计底子平凡人的救星,只要拿着手机或平板拍几张照,房屋或房间的平面图就完成啦!什么?你说听起来很神吗?没错它就是这么神呀!完全不需测量、不需自己拿笔尺绘制、不需…

    2022年5月25日
    161
  • 网站被篡改_网页内容修改

    网站被篡改_网页内容修改   NetCMS的相关新闻显示是根据新闻的Tag来查找所有具有相同的Tag的新闻,然后将其显示的。如,某条新闻的Tag是“工资|奖金”,那么会用下列SQL语句来查找具有相同Tag的新闻:selecttop5*fromahjdcw.NT_NewsWhere[isRecyle]=0And[isLock]=0And[SiteID]=0   And([Tags]L

    2022年9月30日
    0
  • 用Python写了个工具,完美破解了MySQL!!(建议收藏)

    用Python写了个工具,完美破解了MySQL!!(建议收藏)再也不怕忘记MySQL的用户名和密码了,用这个工具可以秒破MySQL,冰河强烈建议收藏!!

    2022年5月31日
    33
  • pycharm激活码2021.12.12_最新在线免费激活

    (pycharm激活码2021.12.12)JetBrains旗下有多款编译器工具(如:IntelliJ、WebStorm、PyCharm等)在各编程领域几乎都占据了垄断地位。建立在开源IntelliJ平台之上,过去15年以来,JetBrains一直在不断发展和完善这个平台。这个平台可以针对您的开发工作流进行微调并且能够提供…

    2022年3月30日
    65

发表回复

您的邮箱地址不会被公开。 必填项已用 * 标注

关注全栈程序员社区公众号