精华内容
下载资源
问答
  • Java中Timer是java.util包中的一个工具类,提供了定时器的功能。我们可以创建一个Timer对象,然后调用其schedule方法在某个特定的时间去执行一个特定的任务。并且你可以让其以特定频率一直执行某个任务,这个任务...

    在Java中Timer是java.util包中的一个工具类,提供了定时器的功能。我们可以创建一个Timer对象,然后调用其schedule方法在某个特定的时间去执行一个特定的任务。并且你可以让其以特定频率一直执行某个任务,这个任务是用TimerTask来描述的,我们只需要将要进行的操作写在TimerTask类的run方法中即可。先附上两个小例子一遍让读者了解什么是定时器。接着再分析其中的一些源码实现。

    第一个小例子:

    package com.zkn.newlearn.thread;

    import java.util.Timer;

    import java.util.TimerTask;

    /**

    * 传统的定时器

    * Created by zkn on 2016/11/1.

    */

    public class TraditionalTimerTest01 {

    public static void main(String[] args){

    //TimerTask是Runnable接口的一个实现类是,它是一个抽像类

    //schedule是一个重载方法:第一个参数TimerTask的实现类。

    // 第二个参数是第一次执行的时间。

    // 第三个参数是间隔时间

    new Timer().schedule(new TimerTask() {

    @Override

    public void run() {

    System.out.println("这是一个定时器任务!");

    }

    },1000,2000);

    }

    }

    第二个小例子:让任务1每隔4秒执行,让任务2每隔2秒执行。依次反复。

    package com.zkn.newlearn.thread;

    import java.util.Timer;

    import java.util.TimerTask;

    /**

    * Created by zkn on 2016/11/1.

    */

    public class TraditionalTimerTest02 {

    public static void main(String[] args){

    new Timer().schedule(new MyTimerTask01(),4000);

    }

    private static class MyTimerTask01 extends TimerTask{

    @Override

    public void run() {

    System.out.println("我是TimerTask1,我被执行了!");

    new Timer().schedule(new MyTimerTask02(),2000);

    }

    }

    private static class MyTimerTask02 extends TimerTask {

    @Override

    public void run() {

    System.out.println("我是TimerTask2,我被执行了!");

    new Timer().schedule(new MyTimerTask01(),4000);

    }

    }

    }

    大家一定会很好奇定时器是怎么执行的?接下来我们来看一下Timer中的主要代码。

    private final TaskQueue queue = new TaskQueue();

    /**

    * The timer thread.

    */

    private final TimerThread thread = new TimerThread(queue);

    注意着两段代码是很重要的两段代码。TaskQueue和TimerThread都是Timer的内部类。TaskQueue是一个执行任务的优先队列。TimerThread是一个继承了Thread的线程类。他们两个在定时器中起着至关重要的作用,定时器基本上就是靠这两个类支撑的。 接下来我们来一下Timer的构造方法:

    public Timer(String name) {

    thread.setName(name);

    thread.start();

    }

    public Timer() {

    this("Timer-" + serialNumber());

    }

    无参的这个构造函数会调用这个有参的构造函数,在这个有参的构造函数中你看到了什么?thread.start()看着是不是很眼熟啊?没错,在new Timer()的时候,就是启动了一个线程。而启动这个线程的对象就是上面的TimerThread!接下来我们来看一下TimerThread的run方法中干了些什么:

    public void run() {

    try {

    mainLoop();

    } finally {

    // Someone killed this Thread,behave as if Timer cancelled

    synchronized(queue) {

    newTasksMayBeScheduled = false;

    queue.clear(); // Eliminate obsolete references

    }

    }

    }

    这个run方法中主要是干了两件事:一:调用mainLoop()这个死循环的方法,我们在下面会详细分析;二:finally代码块终止定时任务。终止定时任务的这个没什么说的,我们主要来看一下mainLoop()这个方法。

    private void mainLoop() {

    while (true) { // 开始死循环

    try {

    TimerTask task;

    boolean taskFired;

    synchronized(queue) {

    // 如果任务队列中为空并且定时任务没有被取消话,线程被挂起 等待执行任务的到来

    while (queue.isEmpty() && newTasksMayBeScheduled)

    queue.wait();

    if (queue.isEmpty())

    break; // 如果任务队列中没有任务了,则结束循环结束任务

    // 如果队列中有执行任务的话,接着往下走

    long currentTime,executionTime;

    task = queue.getMin();

    synchronized(task.lock) {

    if (task.state == TimerTask.CANCELLED) {

    queue.removeMin();

    continue; // 如果执行任务被取消的话 则移除当前任务。这里会重新排队列里的任务执行顺序

    }

    currentTime = System.currentTimeMillis();

    executionTime = task.nextExecutionTime;

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

    if (task.period == 0) { // 如果只执行一次的话,则在执行完之后,结束执行任务

    queue.removeMin();

    task.state = TimerTask.EXECUTED;

    } else { // 如果是固定频率执行任务的话,则计算下次执行的时间

    queue.rescheduleMin(

    task.period<0 ? currentTime - task.period

    : executionTime + task.period);

    }

    }

    }

    if (!taskFired) // 不到任务执行的时候 等待线程调用

    queue.wait(executionTime - currentTime);

    }

    if (taskFired) // 任务执行时间到,调用任务的run方法,执行任务

    task.run();

    } catch(InterruptedException e) {

    }

    }

    }

    这个类比较长,具体的执行操作我在注释里都标注了。这个类基本上干了这样几件事:循环调用任务队列中的任务,执行队列中的任务。执行任务是什么时候放到执行队列中的呢?在schedule方法。我们来看看schedule的实现:

    public void schedule(TimerTask task,long delay,long period) {

    if (delay < 0) // 如果第一次执行的时间小于0 抛出异常

    throw new IllegalArgumentException("Negative delay.");

    if (period <= 0) //间隔时间小于等于 0 抛出异常

    throw new IllegalArgumentException("Non-positive period.");

    sched(task,System.currentTimeMillis()+delay,-period);

    }

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

    if (time < 0)

    throw new IllegalArgumentException("Illegal execution time.");

    // Constrain value of period sufficiently to prevent numeric

    // overflow while still being effectively infinitely large.这个间隔时间到死基本上也执行不到

    if (Math.abs(period) > (Long.MAX_VALUE >> 1))

    period >>= 1;

    synchronized(queue) {

    if (!thread.newTasksMayBeScheduled) //在任务的执行方法中 如果定时任务已经被取消的话 则抛出异常

    throw new IllegalStateException("Timer already cancelled.");

    synchronized(task.lock) { //object对象锁

    if (task.state != TimerTask.VIRGIN) // 刚开是执行任务的时候 任务的状态应该是0的

    throw new IllegalStateException(

    "Task already scheduled or cancelled");

    task.nextExecutionTime = time; //下次执行时间 在上面的mainLoop方法中有用到

    task.period = period; //设置任务的间隔时间,在上面的mainLoop方法中有用到

    task.state = TimerTask.SCHEDULED; // 调度方法被调用 设置定时任务的状态为 已调度未执行

    }

    queue.add(task); //把执行任务加入到任务队列中

    if (queue.getMin() == task)

    queue.notify(); // 如果任务队列中的第一个任务为当前任务的话,则把当前任务放入到等锁池中 等待执行

    }

    }

    shedule这个方法做的事情比较简单。最主要的作用是把TimerTask放到任务队列中。

    下面我们大致看一下TaskQueue的代码:

    class TaskQueue {

    //定义一个TimerTask的堆数组

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

    //任务队列中的任务数

    private int size = 0;

    int size() {

    return size;

    }

    //添加任务到优先队列中 如果数组的长度不够的话会扩展数组

    void add(TimerTask task) {

    // Grow backing store if necessary

    if (size + 1 == queue.length)

    queue = Arrays.copyOf(queue,2*queue.length);

    queue[++size] = task;

    fixUp(size);

    }

    //获取优先执行的任务

    TimerTask getMin() {

    return queue[1];

    }

    TimerTask get(int i) {

    return queue[i];

    }

    //移除掉排在第一位的不能执行的任务

    void removeMin() {

    queue[1] = queue[size];

    queue[size--] = null; // Drop extra reference to prevent memory leak 把对象置空 等待gc回收

    fixDown(1);

    }

    //删除任务队列队列中的任务 这里用来一个断言 来判断 i 不能大于 size

    void quickRemove(int i) {

    assert i <= size;

    queue[i] = queue[size];

    queue[size--] = null; // Drop extra ref to prevent memory leak

    }

    //重新设置优先执行任务的执行时间 并对任务队列进行重新排序 以确保最优先的任务 优先被执行

    void rescheduleMin(long newTime) {

    queue[1].nextExecutionTime = newTime;

    fixDown(1);

    }

    boolean isEmpty() {

    return size==0;

    }

    //清空任务队列 定时任务结束

    void clear() {

    // Null out task references to prevent memory leak

    for (int i=1; i<=size; i++)

    queue[i] = null;

    size = 0;

    }

    //两个堆排序 选出最优先的执行任务

    private void fixUp(int k) {

    while (k > 1) {

    int j = k >> 1;

    if (queue[j].nextExecutionTime <= queue[k].nextExecutionTime)

    break;

    TimerTask tmp = queue[j]; queue[j] = queue[k]; queue[k] = tmp;

    k = j;

    }

    }

    private void fixDown(int k) {

    int j;

    while ((j = k << 1) <= size && j > 0) {

    if (j < size &&

    queue[j].nextExecutionTime > queue[j+1].nextExecutionTime)

    j++; // j indexes smallest kid

    if (queue[k].nextExecutionTime <= queue[j].nextExecutionTime)

    break;

    TimerTask tmp = queue[j]; queue[j] = queue[k]; queue[k] = tmp;

    k = j;

    }

    }

    void heapify() {

    for (int i = size/2; i >= 1; i--)

    fixDown(i);

    }

    }

    OK,到这里定时任务的源码大致分析完毕。

    以上就是本文的全部内容,希望对大家的学习有所帮助,也希望大家多多支持编程小技巧。

    相关文章

    总结

    以上是编程之家为你收集整理的java实现多线程之定时器任务全部内容,希望文章能够帮你解决java实现多线程之定时器任务所遇到的程序开发问题。

    如果觉得编程之家网站内容还不错,欢迎将编程之家网站推荐给程序员好友。

    本图文内容来源于网友网络收集整理提供,作为学习参考使用,版权属于原作者。

    如您喜欢交流学习经验,点击链接加入交流1群:1065694478(已满)交流2群:163560250

    展开全文
  • Java实现线程定时执行任务代码发布时间:2020-05-30 12:23:37来源:亿速云阅读:144作者:鸽子Java多线程中的定时器(java.util.Timer)有定时执行任务的功能,通过设定定时器的间隔时间,会自动在此间隔后执行预先...

    Java实现多线程定时执行任务代码

    发布时间:2020-05-30 12:23:37

    来源:亿速云

    阅读:144

    作者:鸽子

    Java多线程中的定时器(java.util.Timer)有定时执行任务的功能,通过设定定时器的间隔时间,会自动在此间隔后执行预先安排好的任务(java.util.TimerTask)。

    timer.schedule(TimerTask,delay,interval time)

    第一个参数是需要执行的任务。此类的类型为java.util.TimerTask。第二个参数是执行任务前等待时间,第三个参数是间隔时间(单位为毫秒)

    package timer;

    import java.util.concurrent.PriorityBlockingQueue;

    public class MyTimer {

    PriorityBlockingQueue queue = new PriorityBlockingQueue<>();

    Worker worker;private static class Worker extends Thread {

    PriorityBlockingQueue queue;

    Worker(PriorityBlockingQueue queue) {

    this.queue = queue;

    }

    @Override

    public void run() {

    while (true) {

    try {

    MyTimerTask task = queue.take();

    long current = System.currentTimeMillis();

    if (task.delay <= current) {

    task.target.run();

    } else {

    queue.put(task);

    Thread.sleep(task.delay - current);

    }

    } catch (InterruptedException e) {

    e.printStackTrace();

    }

    }

    }

    }

    MyTimer() {

    worker = new Worker(queue);

    worker.start();

    }

    void execute(Runnable target, long delay) {

    queue.put(new MyTimerTask(target, delay));

    }

    public static void main(String[] args) {

    MyTimer timer = new MyTimer();

    timer.execute(new Runnable() {

    @Override

    public void run() {

    System.out.println("该起床了");

    }

    }, 2000);

    System.out.println("另一个人");

    }

    }

    package timer;

    public class MyTimerTask implements Comparable {

    Runnable target;

    long delay;MyTimerTask(Runnable target, long delay) {

    this.target = target;

    this.delay = System.currentTimeMillis() + delay;//延时后的时刻

    }

    @Override

    public int compareTo(MyTimerTask o) {

    if (delay == o.delay) {

    //延时后的时刻

    return 0;

    } else if (delay < o.delay) {

    return -1;

    } else {

    return 1;

    }

    }

    }

    展开全文
  • private static int a=0;public static void main( String[] args ){timer();}public static void timer() {Calendar c = Calendar.getInstance();c.set(Calendar.HOUR_OF_DAY, 10); // 控制时c.set(Calendar.MINUTE...

    private static int a=0;

    public static void main( String[] args )

    {

    timer();

    }

    public static void timer() {

    Calendar c = Calendar.getInstance();

    c.set(Calendar.HOUR_OF_DAY, 10); // 控制时

    c.set(Calendar.MINUTE, 0); // 控制分

    c.set(Calendar.SECOND, 0); // 控制秒

    Date time = c.getTime(); // 得到执行任务的时间,此处为当天的10:00:00

    Timer timer = new Timer();

    timer.scheduleAtFixedRate(new TimerTask() {

    public void run() {

    a++;

    System.out.print(a);

    }

    }, time, 1000);// 这里设定将延时每隔1000毫秒执行一次

    }

    展开全文
  • Java 定时线程

    2021-03-05 15:12:47
    功能需求:项目启动时,后天起一个定时线程,每个小时跑一次,查出数据发邮件出来。主要使用public void schedule(TimerTask task, long delay)task被安排在delay(毫秒)指定的时间后执行。public void schedule...

    功能需求:项目启动时,后天起一个定时线程,每个小时跑一次,查出数据发邮件出来。

    主要使用

    public void schedule(TimerTask task, long delay)

    task被安排在delay(毫秒)指定的时间后执行。

    public void schedule(TimerTask task,long delay, long period)

    task被安排在delay(毫秒)指定的时间后执行。执行后将每隔period(毫秒)反复执行。

    public void scheduleAtFixedRate(TimerTask task,Date firstTime, long period)

    task被安排在firstTime指定的时间执行。执行后将每隔period(毫秒)反复执行。每一次重复的时间时盒第一次执行而不是和前一次执行有关。因此执行的总速度是固定的。

    public void scheduleAtFixedRate(TimerTask task,long delay,long period)

    task被安排在delay(毫秒)指定的时间后执行。执行后将每隔period(毫秒)反复执行。每一次重复的时间时盒第一次执行而不是和前一次执行有关。因此执行的总速度是固定的。

    package com.odianyun.ad.service.alertMailJob;

    import com.odianyun.ad.business.read.manage.AdSourceReadManage;

    import com.odianyun.ad.business.utils.ConfigUtil;

    import com.odianyun.ad.model.po.AdSourcePO;

    import com.odianyun.hotword.business.read.manage.HotWordReadManage;

    import com.odianyun.hotword.business.read.manage.impl.HotWordReadManageImpl;

    import com.odianyun.search.whale.common.util.EmailUtil;

    import com.odianyun.search.whale.common.util.NetUtil;

    import org.apache.commons.collections.CollectionUtils;

    import org.apache.log4j.Logger;

    import org.springframework.beans.factory.annotation.Autowired;

    import org.springframework.stereotype.Service;

    import javax.mail.MessagingException;

    import java.util.*;

    public class ExpiredJob {

    static Logger logger = Logger.getLogger(ExpiredJob.class);

    @Autowired

    AdSourceReadManage adSourceReadManage;

    @Autowired

    HotWordReadManage hotWordReadManage;

    private static long sendIntervalMinus;

    private static boolean isSendErrorMail;

    private static String sendTo;

    static {

    ConfigUtil.loadPropertiesFile("mail.properties");

    sendIntervalMinus = ConfigUtil.getLong("mail.sendIntervalMinus", 60);

    isSendErrorMail = ConfigUtil.getBool("mail.isSendErrorMail", true);

    sendTo = ConfigUtil.get("mail.msgTo");

    }

    public ExpiredJob() {

    //现在构造函数里面,然后在spring bean的配置文件里增加这个bean,让spring容器创建这个实例,也就达到了项目启动时启动线程的目的

    //线程用于扫描24小时以内即将过期的广告

    //此线程启动后开始执行,每一个小时执行一次

    Timer timer = new Timer(false);

    timer.scheduleAtFixedRate(new TimerTask() {

    public void run() {

    try {

    List adlist = adSourceReadManage.getExpiredAdSource();

    List hotwordlist = hotWordReadManage.getExpiredHotWordIds();

    if (CollectionUtils.isNotEmpty(adlist)) {

    StringBuffer sb = new StringBuffer();

    for(AdSourcePO adSourcePO : adlist){

    sb.append("广告名称 : " + adSourcePO.getName() + " ,广告位 : " +adSourcePO.getCodeName() +" ");

    }

    EmailUtil.sendMail("Below " + adlist.size() + " ads will be expired in 24 hours , send from " + NetUtil.getLocalIP(), sendTo, sb);

    logger.info("Send ad " + adlist.toString() + " mail successfully");

    } else {

    logger.info("No ads will expired in 24 hours.");

    }

    if (CollectionUtils.isNotEmpty(hotwordlist)) {

    EmailUtil.sendMail("Below " + hotwordlist.size() + " hot words will be expired in 24 hours , send from " + NetUtil.getLocalIP(), sendTo, hotwordlist);

    logger.info("Send hot words " + hotwordlist.toString() + " mail successfully");

    } else {

    logger.info("No hot words will expired in 24 hours.");

    }

    } catch (Exception e) {

    logger.error("Send ad expired mail exception", e);

    }

    }

    }, 1000 * 60 * 1, 1000 * 60 * sendIntervalMinus);

    }

    ;

    }

    展开全文
  • java线程定时任务

    2021-02-12 14:17:43
    c、缺乏更多功能,如定时执行、定期执行、线程中断。Java提供的四种线程池的好处在于:a、重用存在的线程,减少对象创建、消亡的开销,性能佳。b、可有效控制最大并发线程数、提供系统资源的使用率,同时避免过多...
  • java定时线程停止

    2021-02-26 09:00:34
    展开全部我这儿有一个过年前写的定时关机32313133353236313431303231363533e4b893e5b19e31333238643631程序你可以拿去参考下~程序里的取消功能跟你要的差不多import java.awt.FlowLayout;import java.awt....
  • 一、Java线程实现方式java实现线程的方式有三种,接下来我将会逐个进行介绍。1.继承Thread类继承Thread类是Java中比较常见,也是很基础的一种实现Java线程的方式。实现的方式也比较简单,只要将需要实现多...
  • 1.最近参与的项目,设计了一套定时任务系统,实现如下: 1.初始化任务 ScheduledFuture<?> future = threadPoolTaskScheduler.schedule((Runnable) Class.forName(cron.getCronClass()).newInstance(), new ...
  • Java如何实现定时任务

    2021-02-26 16:51:04
    在我们编程过程中如果需要执行一些简单的定时任务,无须做复杂的控制,我们可以考虑使用JDK中的Timer定时任务来实现。下面LZ就其原理、实例以及Timer缺陷三个方面来解析java Timer定时器。一、简介在java中一个完整...
  • [java]代码库public class ThreadTest extends HttpServlet implements Runnable {public void run() {try {Calendar c;while(true){c=Calendar.getInstance();//时间对象int mm=30;//默认线程间隔时间System.out....
  • //可以启动一个线程来做时间计算//也可以用timer来实现定时 timer使用wait 我这里用sleep//关键不是用什么而是用线程来解决问题import java.util.Scanner;public class Test {public static void main(String[] args...
  • 前几篇文章中分别介绍了单线程化线程池(newSingleThreadExecutor)可控最大并发数线程池(newFixedThreadPool)可回收缓存线程池(newCachedThreadPool)newScheduledThreadPool用于构造安排线程池,能够根据需要安排在...
  • java项目中如何利用多线程实现一个定时器任务发布时间:2020-11-10 16:04:03来源:亿速云阅读:86作者:Leah今天就跟大家聊聊有关java项目中如何利用多线程实现一个定时器任务,可能很多人都不太了解,为了让大家...
  • java实现定时功能

    2021-02-27 17:00:02
    网上资料:我们可以使用Timer和TimerTask类在java实现定时任务,详细说明如下:1、基础知识java.util.Timer一种线程设施,用于安排以后在后台线程中执行的任务。可安排任务执行一次,或者定期重复执行。此类是线程...
  • 今天我们不用任何框架,用最朴素的 Java API 来实现定时任务,本文会介绍3 种实现方案,我们一起来看...1、 sleep 这也是我们最常用的 sleep 休眠大法,不只是当作休眠...
  • Java实现定时任务,一般都是用一个线程,设置个时间,让他定时执行,注意力一般都是集中在这个线程实现,很少考虑到具体定时执行线程的这个过程。scheduleAtFixedRate 和 scheduleWithFixedDelay 的差别大吗?要是...
  • JAVA平台,实现异步调用的角色有如下三个角色:调用者 提货单 真实数据一个调用者在调用耗时操作,不能立即返回数据时,先返回一个提货单.然后在过一断时间后凭提货单来获取真正的数据.去蛋糕店买蛋糕,不需要等蛋糕做...
  • 今天咱们实现一个单线程实例模式,也就是说只能实例化该类的一个线程来运行,不容许有该类的多个线程实例存在。直接上代码:javapublic class SingletonThread implementsRunnable{/**获取access_token 和 expire_in...
  • 在现实世界里,我们总是免不了要定期去做一件事情(比如上课)—— ...在 使用线程池 中已经介绍,JDK 1.5 时,标准类库添加了对线程池的支持,然后在线程池核心实现 ThreadPoolExecutor 的基础上,实现了 ScheduledTh...
  • (手机横屏看源码更方便)注:java源码分析部分如无特殊说明均基于 java8 版本。注:本文基于ScheduledThreadPoolExecutor定时线程池类。简介前面我们一起学习了普通任务、未来任务的执行流程,今天我们再来学习一种新...
  • 本文实例为大家分享了java线程实现文件下载的具体代码,供大家参考,具体内容如下1、DownloadManager类import java.io.File;import java.io.FileInputStream;import java.io.FileOutputStream;import java.io....
  • 前言现代的应用程序早已不是以前的那些由简单的增删改查拼凑而成的程序了,高复杂性早已是标配,而任务的定时...java 系统中主要有三种方式来实现定时任务:Timer和TimerTaskScheduledExecutorService三方框架 Quar...
  • Java线程实现及四种线程池和new Thread的使用及差别 线程的生命周期分为:new,runnable,running,block,termate. java线程的几种实现方式: 继承Thread类,重写run方法 实现Runnable接口,重写run方法,实现...
  • Java线程实现方式主要有三种:继承Thread类、实现Runnable接口、使用ExecutorService、Callable、Future实现有返回结果的多线程。其中前两种方式线程执行完后都没有返回值,只有最后一种是带返回值的。1、继承...
  • 最近在做一个需求:从其他系统的ftp目录下载存储图片url的文件,然后读取文件中的url地址,根据地址下载图片后按天压缩成一个包,平均一个地址...使用框架:SpringMVC定时任务实现:继承org.springframework.sche...
  • import java.lang.management.ManagementFactory;import java.util.List;import java.util.concurrent.atomic.AtomicBoolean;import org.springframework.util.CollectionUtils;import ...
  • Java:定时启动线程

    2021-03-15 01:25:59
    一是通过java.util.concurrent.DelayQueue实现;二是通过java.util.concurrent.ScheduledThreadPoolExecutor实现。1. java.util.concurrent.DelayQueue类DelayQueue是一个×××阻塞队列,只有在延迟期满时才能从中...
  • 先说一种Java自带的java.util包里的计时器Timer类,线程调度任务以供将来在后台线程中执行的功能。任务可以安排一次执行,或定期重复执行。在进行Timer对象的新建时,Timer提供了多种有参构造和无参构造,主要区别...

空空如也

空空如也

1 2 3 4 5 ... 20
收藏数 108,555
精华内容 43,422
关键字:

java线程实现定时

java 订阅