java多线程之定时器

这篇具有很好参考价值的文章主要介绍了java多线程之定时器。希望对大家有所帮助。如果存在错误或未考虑完全的地方,请大家不吝赐教,您也可以点击"举报违法"按钮提交疑问。

一、 简介

1. 概念

定时功能在java中主要是通过 Timer类实现,因为它在内部还是使用多线程的方式进行处理,所以和多线程技术还是有非常大的管理

2. 定时器的使用

在JDK库中Timer类主要负责计划任务的功能,也就是在指定时间开始执行某一个任务,Timer类的主要功能就是设置计划任务,封装任务的类确是TimerTask,因为TimerTask是一个抽象类,所以执行计划任务的代码要放入TimerTask子类中。

二、 常用方法介绍

1. Schedule(TimTask task,Data time)

该方法的作用是在指定的日期执行一次某一任务

  1. 执行任务的时间晚于当前时间(在未来执行)的效果

如果Data time,该参数的时间晚于现在的时间就是未来执行,而该参数的时间早于现在的执行就是立即执行的意思

测试代码如下

public class Main {
    public static void main(String[] args) throws InterruptedException {
        long nowTime=System.currentTimeMillis();
        System.out.println("当前时间为:"+nowTime);

        //计划时间比当前晚10s
        long scheduleTime=(nowTime+10000);
        Mytest task=new Mytest();
        Timer timer=new Timer();
        Thread.sleep(1000);
        timer.schedule(task,new Date(scheduleTime));

        Thread.sleep(Integer.MAX_VALUE);

    }
}
class Mytest extends TimerTask{
    @Override
    public void run() {
        System.out.println("任务执行了,时间为:"+System.currentTimeMillis());

    }

}

测试后你会发现过了一段时间才执行TimerTask中的任务

  1. 线程TimerThread不销毁的原因

其实上面10s后任务虽然执行完了,但是进程并没有销毁,因为创建Timer类的同时会创建一个新进程(TimerThread—实现计时器的任务执行线程,该线程等待计时器队列上的任务,在触发时执行它们,重新计划重复任务,并从队列中删除已取消的任务和已花费的非重复任务),Timer源码如下:

java多线程之定时器
(图中应该是线程,有笔误)

而这线程是进程不结束的原因,因为它的run方法调用了一个mainLoop方法,该方法内部有个死循环,只有到达特定要求才会退出死循环,我们看它源码:

 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) {
            }
        }
    }
}
  • 使用while循环对queue.isempty()&&newTasksMayBescheduled条件进行判断
  • 当满足时,执行wait方法暂停该线程,等待被唤醒
  • 唤醒的时机是执行了public void schedule(TimeTask task ,Data time)方法,说明要执行新的任务了
  • 唤醒后while继续判断前面的条件,如果有新的任务被安排,则会向下继续执行
  • if(queue.isempty())判断结果为true的时候,说明队列为空,那么执行break退出死循环
  • 如果不执行public void cancel()方法会使布尔变量newTasksMayBeSchedule的值由true变为false,进程不销毁就是这个原因,cancel源码如
    public void cancel() {
        synchronized(queue) {
            thread.newTasksMayBeScheduled = false;
            queue.clear();
            queue.notify();  // In case queue was already empty.
        }
    }

cancel方法的作用就是终止计时器,丢弃当前所有已安排的任务。这不会干扰正在执行的任务,一旦终止计时器,那么它的执行线程也会终止,并且无法根据它安排更多的任务。注意,在此计时器调用的计时器任务的run()方法内调用此方法,就可以确保正在执行的任务就是所执行的最后一个任务,虽然可以重复调用cancel方法,但后面都是无效的。

  1. 在定时器中执行多个TimerTask任务

创建的方法如下

//创建一个Timer
TImer timer= new Timer();
//创建多个任务
MyTask task1=new MyTask();
MyTask task2=new MyTask();
//执行schedule方法
timer.schedule(task1,new Date(scheduleTime1));
timer.schedule(task2,new Date(scheduleTime2));

由于多个任务的存在,因为TimerTask是以队列的方式一个一个被顺序执行的,所以执行时间有可能和预期的时间不一致,这是因为前面的任务可能执行时间过长,导致后面的任务被延时

2. Schedule(TimTask task,Data firstTime, long period)

改方法的作用是在指定的日期之后按指定的间隔周期无限地执行某一个任务,参数firstTime是循环任务开始的时间,period是任务循环的,和上面介绍的方法一样,该方法也有上面方法的特性:

  • 执行任务的时间晚于当前时间:任务会从指定时间开始,在指定的时间周期内开始循环执行任务
  • 执行任务的时间早于当前时间:任务同样会立即开始执行,且在指定的时间间隔内循环执行
  • 延时问题:同样该方法也会存在任务延时执行的问题
  • cancel方法:前面介绍了Timer类的cancel方法的特性它会终止所有没有执行的任务(清除队列中所有任务),而TimerTask类中的方法的作用是将自身从任务队列中消除,源码如下,可见该方法时将当前TimerTask任务的状态改为CANCELLED
   public boolean cancel() {
        synchronized(lock) {
            boolean result = (state == SCHEDULED);
            state = CANCELLED;
            return result;
        }
    }
  • 同一时间间隔内执行多个循环任务:算法是,当队列中有3个任务ABC时,这3个任务的执行顺序的算法是每次将最后一个任务放入队列头,在再执行队列头中任务的run方法。例如,ABC,CAB,BCA以此类推

3. Schedule(TimTask task, long delay)

该方法的作用是以执行schedule(Timer task, long delay)方法当前的时间为参考时间,在此时间基础上延迟指定的毫秒数后执行一次TimerTask任务

4. Schedule(TimTask task, long delay, long period)

该方法的作用是以当前时间为参考时间,在此基础上延迟指定的毫秒数,再以某一时间为间隔无限次数地执行某一任务。

5. scheduleAtFixedRate(TimerTask task, Date firstTime,long period)

schedule方法和scheduleAtFixedRate方法的主要区别在于有没有追赶特性

  1. 测试schedule方法任务不延时(Date类型-其实就是Schedule(TimTask task,Data firstTime, long period)

代码测试如下:

public class Main {
    public static void main(String[] args) throws InterruptedException {
         Mytest task=new Mytest();
         long nowTime=System.currentTimeMillis();
         Timer timer=new Timer();
         timer.schedule(task,new Date(nowTime),3000);

    }
}
class Mytest extends TimerTask{
    @Override
    public void run() {
       try{
           System.out.println("begin timer="+System.currentTimeMillis());
           Thread.sleep(1000);
           System.out.println("end timer"+System.currentTimeMillis());
       }catch (InterruptedException e) {
           e.printStackTrace();
       }

    }

}

java多线程之定时器
由结果可以知道,在不延时的情况下,如果执行任务的时间没有被延时,则下一次执行任务的开始时间就是上一次任务的开始时间加上Period时间,所谓的“不延时”是指执行任务的时间小于或等于period时间间隔

  1. 测试schedule方法任务不延时(long类型-其实就是Schedule(TimTask task, long delay, long period)

代码测试如下:

public class Main {
    public static void main(String[] args) throws InterruptedException {
         Mytest task=new Mytest();
         long nowTime=System.currentTimeMillis();
         Timer timer=new Timer();
         timer.schedule(task,new 3000,3000);

    }
}
class Mytest extends TimerTask{
    @Override
    public void run() {
       try{
           System.out.println("begin timer="+System.currentTimeMillis());
           Thread.sleep(1000);
           System.out.println("end timer"+System.currentTimeMillis());
       }catch (InterruptedException e) {
           e.printStackTrace();
       }

    }

}

java多线程之定时器
在不延时的情况下,如果执行任务的时间没有被延时,则第一次执行任务的时间是任务开始的时间加上被延迟的时间,接下来执行任务的时间是上一次的开始时间加上period时间

  1. 测试shceudle方法的任务延迟(Date类型)
public class Main {
    public static void main(String[] args) throws InterruptedException {
         Mytest task=new Mytest();
         long nowTime=System.currentTimeMillis();
         Timer timer=new Timer();
         timer.schedule(task,new Date(nowTime),2000);

    }
}
class Mytest extends TimerTask{
    @Override
    public void run() {
       try{
           System.out.println("begin timer="+System.currentTimeMillis());
           Thread.sleep(5000);
           System.out.println("end timer"+System.currentTimeMillis());
       }catch (InterruptedException e) {
           e.printStackTrace();
       }

    }

}

java多线程之定时器
从控制台打印的结果可以看出,在延时的情况下,如果执行任务的时间被延时,那么下一次任务的执行时间参考的时上一次任务“结束”的时间,同样子long类型也是这样,同样scheduleAtFixedRate在long和date类型下在延迟和不延迟的情况下都是一样的

  1. 验证schedule方法不具有追赶执行性
    执行下面代码
public class Main {
    public static void main(String[] args) throws InterruptedException {
         Mytest task=new Mytest();
         long nowTime=System.currentTimeMillis();
        System.out.println("现在执行时间:"+nowTime);
        long runtime=nowTime-20000;
        System.out.println("计划执行时间:"+runtime);
        Timer timer=new Timer();
        timer.scheduleAtFixedRate(task,new Date(runtime),2000);

    }
}
class Mytest extends TimerTask{
    @Override
    public void run() {
           System.out.println("begin timer="+System.currentTimeMillis());
           System.out.println("end timer"+System.currentTimeMillis());
    }

}

java多线程之定时器

由结果可以看出,计划在1684417340323和1684417320323之间的任务没有追赶执行,所谓的追赶执行,就是原来计划在前面那段时间的任务,由于时间已经过了,只能从现在开始给它补上来,这就是追赶。而该方法也有追赶执行性文章来源地址https://www.toymoban.com/news/detail-454652.html

到了这里,关于java多线程之定时器的文章就介绍完了。如果您还想了解更多内容,请在右上角搜索TOY模板网以前的文章或继续浏览下面的相关文章,希望大家以后多多支持TOY模板网!

本文来自互联网用户投稿,该文观点仅代表作者本人,不代表本站立场。本站仅提供信息存储空间服务,不拥有所有权,不承担相关法律责任。如若转载,请注明出处: 如若内容造成侵权/违法违规/事实不符,请点击违法举报进行投诉反馈,一经查实,立即删除!

领支付宝红包 赞助服务器费用

相关文章

  • 【Java|多线程与高并发】定时器(Timer)详解

    在Java中,定时器 Timer 类是用于执行定时任务的工具类。它允许你安排一个任务在未来的某个时间点执行,或者以固定的时间间隔重复执行。 在服务器开发中,客户端向服务器发送请求,然后等待服务器响应. 但服务器什么时候返回响应,并不确定. 但也不能让客户端一直等下去

    2024年02月07日
    浏览(45)
  • 【多线程】定时器,详解定时器原理,让大家更深刻的理解多线程

    前言: 大家好,我是 良辰丫 ,今天我们一起了解一下定时器,通过定时器来熟悉一下线程安全等相关知识点.💞💞💞 🧑个人主页:良辰针不戳 📖所属专栏:javaEE初阶 🍎励志语句:生活也许会让我们遍体鳞伤,但最终这些伤口会成为我们一辈子的财富。 💦期待大家三连,关注

    2024年02月01日
    浏览(60)
  • 多线程---定时器

    定时器的功能和“闹钟”类似,代码中的定时器通常都是“多长时间之后,执行某个动作”。 注: 一个定时器可以安排多个任务。 调用schedule安排任务时,一定要重写run方法,明确任务内容 定时器开启后不会自动结束,得手动杀死进程 版本一:实现简单的定时器 schedule方法

    2024年02月08日
    浏览(39)
  • 多线程案例(3)-定时器

    大家好,我是晓星航。今天为大家带来的是 多线程案例三 相关的讲解!😀 定时器是什么 定时器也是软件开发中的一个重要组件. 类似于一个 “闹钟”. 达到一个设定的时间之后, 就执行某个指定 好的代码. 定时器是一种实际开发中非常常用的组件. 比如网络通信中, 如果对方

    2024年02月14日
    浏览(42)
  • 【javaEE】阻塞队列、定时器、线程池

    目录 🌴一、阻塞队列 1.概念 2.生产者消费者模型 3.阻塞队列的实现 🏹二、定时器 1.引出定时器 2.定时器的实现 🔥三、线程池 1.引出线程池 2.ThreadPoolExecutor 构造方法 3.标准数据库的4种拒绝策略【经典面试题】【重点掌握】 4.线程池的实现   1.概念 ✨对于队列,首先我们想

    2023年04月21日
    浏览(44)
  • 多线程案例 | 单例模式、阻塞队列、定时器、线程池

    单例模式 单例模式是 设计模式 的一种 什么是设计模式? 设计模式好比象棋中的 “棋谱”,红方当头炮,黑方马来跳,针对红方的一些走法,黑方应招的时候有一些固定的套路,按照套路来走局势就不会吃亏,也就发明了一组\\\"棋谱\\\",称为设计模式 软件开发中也有很多常见

    2024年02月15日
    浏览(48)
  • 【JavaEE初阶】多线程(四)阻塞队列 定时器 线程池

    概念 阻塞队列是一种特殊的队列. 也遵守 “ 先进先出 ” 的原则. 阻塞队列能是一种线程安全的数据结构, 并且具有以下特性: 当队列满的时候, 继续入队列就会阻塞, 直到有其他线程从队列中取走元素. 当队列空的时候, 继续出队列也会阻塞,直到有其他线程往队列中插入元素

    2023年04月26日
    浏览(54)
  • JavaEE & 线程案例 & 定时器 & 线程池 and 工厂模式

    欢迎光临 ^ V ^ 定时器,可以理解为闹钟 我们设立一个时间,时间一到,让一个线程跑起来~ 而Java标准库提供了一个定时器类: Timer ,from java.util 1.1 定时器Timer的使用 1.1.1 核心方法schedule 传入任务引用(TimerTask task)和 “定时”(long delay / ms) 由于TimerTask不是函数式接口,

    2023年04月18日
    浏览(44)
  • STC89C52定时器的简介

    针对于STC89C52RC而言,这个芯片内部包含了三个定时器——T0、T1和T2,他们的中断优先级分别是1、3和5。 怎么还有一个定时器2呢?博主也是今天整理这篇博客的时候,翻阅芯片手册才发现的。如果说,我们经常用的T0和T1叫做通用定时器的话,那么T2我愿称之为高级定时器。今

    2024年02月05日
    浏览(47)
  • C++ 实现定时器的两种方法(线程定时和时间轮算法修改版)

    定时器要求在固定的时间异步执行一个操作,比如boost库中的boost::asio::deadline_timer,以及MFC中的定时器。也可以利用c++11的thread, mutex, condition_variable 来实现一个定时器。 1、使用C++11中的thread, mutex, condition_variable来实现一个定时器。 注:此算法会每一个任务创建一个线程,不推

    2024年02月05日
    浏览(50)

觉得文章有用就打赏一下文章作者

支付宝扫一扫打赏

博客赞助

微信扫一扫打赏

请作者喝杯咖啡吧~博客赞助

支付宝扫一扫领取红包,优惠每天领

二维码1

领取红包

二维码2

领红包