设为首页收藏本站
网站公告 | 这是第一条公告
     

 找回密码
 立即注册
缓存时间13 现在时间13 缓存数据 到现在一共是295天,有了人生中第一张迷你专辑,我期许自己这不会是句号,只会是个逗号,会一直一直一直突破的,直到我唱不动的那天。

到现在一共是295天,有了人生中第一张迷你专辑,我期许自己这不会是句号,只会是个逗号,会一直一直一直突破的,直到我唱不动的那天。 -- 一种原谅

查看: 1179|回复: 3

Java任务定时执行器案例的实现

[复制链接]

  离线 

TA的专栏

  • 打卡等级:热心大叔
  • 打卡总天数:233
  • 打卡月天数:0
  • 打卡总奖励:3407
  • 最近打卡:2025-04-21 04:13:29
等级头衔

等級:晓枫资讯-上等兵

在线时间
0 小时

积分成就
威望
0
贡献
415
主题
382
精华
0
金钱
4661
积分
867
注册时间
2023-1-7
最后登录
2025-4-21

发表于 2023-2-17 13:44:31 | 显示全部楼层 |阅读模式
⭐️前面的话⭐️

本篇文章将介绍Java多线程案例,定时器,定时器就像闹钟一样,等到了指定的时间,闹钟就会发出响声来提醒您,而定时器会执行指定的任务。

🍎1.定时器概述


🍏1.1认识定时器

java中的定时器,也可以叫做任务定时执行器,顾名思义,就是等到了指定的时间,就去做指定的事情,就像你每周六或周日都要去力扣参加周赛一样。
所以你如果想要使用定时器,你需要交代时间和对应的任务才行,java标准也提供了带有定时器功能的类
  1. Timer
复制代码


🍏1.2Timer类的使用

在java1.8中,Timer给出了四个构造方法,这些构造方法可以去指定线程的名字和是否将定时器内部的线程指定为守护线程。
好了,又出现了一个新概念,这个守护线程是什么鬼?
其实在java中有两种线程,一种是用户线程,另外一种是守护线程。用户线程就是普通的线程,守护线程顾名思义就是守护用户线程的线程,可以说就是用户线程的保姆,守护线程与JVM“共存亡”, 只要存在一个用户线程,程序中所有的守护线程都不会停止工作,直到最后一个用户线程执行完毕,守护线程才会停止工作。守护线程最典型的应用就是 GC (垃圾回收器),它就是一个非常称职的守护者。
🍊构造方法:
序号构造方法说明1public Timer()无参数构造方法,默认定时器关联的线程不是守护线程,线程名字也是默认值2public Timer(boolean isDaemon)指定定时器中关联的线程是否为守护线程,如果是,参数为true3public Timer(String name)指定定时器关联线程名称,线程类型默认为非守护线程4public Timer(String name, boolean isDaemon)指定定时器关联线程名和线程类型Timer类构造时内部也会创建线程,如果不指定,定时器对象内部的线程(为了简化,就称为关联线程吧)的类型是用户线程,而不是守护线程。
🍊核心方法:
序号方法说明1public void schedule(TimerTask task, long delay)指定任务,延迟多久执行该任务2public void schedule(TimerTask task, Date time)指定任务,指定任务的执行时间3public void schedule(TimerTask task, long delay, long period)连续执行指定任务,延迟时间,连续执行任务的时间间隔,毫秒为单位4public void schedule(TimerTask task, Date firstTime, long period)连续执行指定任务,第一次任务的执行时间,连续执行任务的时间间隔5public void scheduleAtFixedRate(TimerTask task, Date firstTime, long period)与方法4作用相同6public void scheduleAtFixedRate(TimerTask task, long delay, long period)与方法3作用相同7public void cancel()终止定时器所有任务,终止执行的任务不受影响🍊使用演示:
  1. import java.util.Timer;
  2. import java.util.TimerTask;
  3. import java.util.concurrent.PriorityBlockingQueue;

  4. public class TimeProgram {
  5.     public static void main(String[] args) throws InterruptedException {
  6.         Timer timer = new Timer();
  7.         timer.schedule(new TimerTask() {
  8.             @Override
  9.             public void run() {
  10.                 System.out.println("执行延后2s执行的任务!");
  11.             }
  12.         }, 2000);
  13.         timer.schedule(new TimerTask() {
  14.             @Override
  15.             public void run() {
  16.                 System.out.println("执行延后5s执行的任务!");
  17.             }
  18.         }, 5000);

  19.         //每秒输出一个mian
  20.         for (int i = 0; i < 5; i++) {
  21.             System.out.println("main");
  22.             Thread.sleep(1000);
  23.         }
  24.     }
  25. }
复制代码
🍊运行结果:
144521frmm8pldyewymgym.jpeg

TimerTask类就是专门描述定时器任务的一个抽象类,它实现了Runnable接口。
  1. public abstract class TimerTask implements Runnable    //jdk源码
复制代码
下面我们简单实现一下定时器,我们就不用TimerTask了,我们直接使用Runnable,因为TimerTask实现了Runnable接口,所以后面测试我们自己所写的
  1. schedule
复制代码
方法时,也可以传入TimerTask类型的引用,既然是简单地实现,那就不实现连续执行的功能了。

🍎2.定时器的简单实现

首先,我们需要建造一个类,来描述定时器的任务,可以使用Runnable加上一个任务执行的时间戳就可以了。
🍊具体清单:
一个构造方法,用来指定任务和延迟执行时间。
两个获取方法,用来给外部对象获取该对象的任务和执行时间。
实现比较器,用于定时器任务对象的组织,毕竟,每次需要执行时间最早的任务,需要用到基于小根堆实现的优先队列,不,还需要考虑多线程的情况,还是使用优先级阻塞队列吧。
  1. //我的任务
  2. class MyTask implements Comparable<MyTask> {
  3.     //接收具体任务
  4.     private Runnable runnable;
  5.     //执行时的时间戳
  6.     private long time;

  7.     //构造方法
  8.     public MyTask(Runnable runnable, int delay) {
  9.         this.runnable = runnable;
  10.         this.time = System.currentTimeMillis() + delay;
  11.     }

  12.     //执行任务
  13.     public void run() {
  14.         this.runnable.run();
  15.     }
  16.     //获取执行时间
  17.     public long getTime() {
  18.         return this.time;
  19.     }

  20.     //实现comparable接口,方便创建优先级阻塞队列
  21.     @Override
  22.     public int compareTo(MyTask o) {
  23.         return (int) (this.time - o.time);
  24.     }
  25. }
复制代码
接下来就要实现定时器类了,首先我们需要一个数据结构来组织定时器任务,并且每次都能将时间最早的任务找到并执行,那么这个数据结构非小根堆莫属了,也就是优先级队列,注意对自定义类使用优先级队列时,一定要实现比较器。
  1.     //每次执行任务时,需要优先执行时间在前的任务,即每次执行任务要选择时间戳最小的任务,在多线程情况中优先级阻塞队列是最佳选择
  2.     private static final PriorityBlockingQueue<MyTask> priorityBlockingQueue = new PriorityBlockingQueue<>();
复制代码
然后,需要一个方法将任务安排在优先级阻塞队列中,最后在构造定时器对象的时候从优先级阻塞队列中取任务并在指定的时间执行。
144521navh21c97dhahvc2.jpeg

按照上图的逻辑,我们自己实现的定时器类需要有一个线程专门去执行任务,执行任务过程中可能会遇到执行时间还没有到的情况,那么线程必须得等待,线程等待的方法有两种,一种是
  1. wait
复制代码
另一种是
  1. sleep
复制代码
,这个案例我们推荐前者,因为
  1. sleep
复制代码
方法不能中途唤醒,这个案例是有可能需要中途唤醒的,那就是有新任务插入时,需要重新去优先级阻塞队列拿任务重复上述操作,这个唤醒操作可以使用
  1. notify
复制代码
方法实现,所以需要用到
  1. wait/notify
复制代码
组合拳,既然需要使用
  1. wait/notify
复制代码
那么就得有锁,所以我们可以使用一个专门的锁对象来加锁。
144522p6wi7pjyae6aee7s.jpeg

🍊实现代码:
  1. //我的定时类 用来管理任务class MyTimer {    //专门对锁对象    private final Object locker = new Object();    //每次执行任务时,需要优先执行时间在前的任务,即每次执行任务要选择时间戳最小的任务,在多线程情况中优先级阻塞队列是最佳选择
  2.     private static final PriorityBlockingQueue<MyTask> priorityBlockingQueue = new PriorityBlockingQueue<>();    //安排任务    public void schedule(Runnable runnable, int delay) {        //将任务放入小根堆中        MyTask task = new MyTask(runnable, delay);        priorityBlockingQueue.put(task);        //每次当新任务加载到阻塞队列时,需要中途唤醒线程,因为新进来的任务可能是最早需要执行的        synchronized (locker) {            locker.notify();        }    }    public MyTimer() {        Thread thread = new Thread(() -> {            while (true) {                try {                    //加载任务,确定执行时机                    MyTask myTask = priorityBlockingQueue.take();                    long curTime = System.currentTimeMillis();                    //时间未到,将任务放回                    if (curTime < myTask.getTime()) {                        synchronized (locker) {                            priorityBlockingQueue.put(myTask);                            //放回任务后,不能立即就再次取该任务加载,需要设置一个再次加载的等待时间,建议使用wait带参数的方法                            //因为wait方法可以使用notify进行中途唤醒,而sleep不能中途唤醒                            int delay = (int)(myTask.getTime() - curTime);                            locker.wait(delay);                        }                    } else {                        System.out.println(Thread.currentThread().getName() + "线程收到任务,正在执行中!");                        myTask.run();                        System.out.println(Thread.currentThread().getName() + "线程执行任务完毕,正在等待新任务!");                    }                } catch (InterruptedException e) {                    e.printStackTrace();                }            }        });        //不要忘了启动线程        thread.start();    }}
复制代码
🍊上面是我们实现定时器的代码,我们来测试一下:
  1. import java.util.TimerTask;
  2. import java.util.concurrent.PriorityBlockingQueue;

  3. public class TimeProgram {
  4.     public static void main(String[] args) throws InterruptedException {
  5.         MyTimer timer = new MyTimer();
  6.         timer.schedule(new TimerTask() {
  7.             @Override
  8.             public void run() {
  9.                 System.out.println("执行延后2s执行的任务!");
  10.             }
  11.         }, 2000);
  12.         timer.schedule(new TimerTask() {
  13.             @Override
  14.             public void run() {
  15.                 System.out.println("执行延后5s执行的任务!");
  16.             }
  17.         }, 5000);

  18.         //每秒输出一个mian
  19.         for (int i = 0; i < 5; i++) {
  20.             System.out.println("main");
  21.             Thread.sleep(1000);
  22.         }
  23.     }
  24. }
复制代码
🍊执行结果:
144522zctbb3lfwbgv48lb.jpeg

好了,任务定时执行器你学会了吗?
到此这篇关于Java任务定时执行器案例的实现的文章就介绍到这了,更多相关Java任务定时执行器内容请搜索晓枫资讯以前的文章或继续浏览下面的相关文章希望大家以后多多支持晓枫资讯!

免责声明:如果侵犯了您的权益,请联系站长,我们会及时删除侵权内容,谢谢合作!
晓枫资讯-科技资讯社区-免责声明
免责声明:以上内容为本网站转自其它媒体,相关信息仅为传递更多信息之目的,不代表本网观点,亦不代表本网站赞同其观点或证实其内容的真实性。
      1、注册用户在本社区发表、转载的任何作品仅代表其个人观点,不代表本社区认同其观点。
      2、管理员及版主有权在不事先通知或不经作者准许的情况下删除其在本社区所发表的文章。
      3、本社区的文章部分内容可能来源于网络,仅供大家学习与参考,如有侵权,举报反馈:点击这里给我发消息进行删除处理。
      4、本社区一切资源不代表本站立场,并不代表本站赞同其观点和对其真实性负责。
      5、以上声明内容的最终解释权归《晓枫资讯-科技资讯社区》所有。
http://bbs.yzwlo.com 晓枫资讯--游戏IT新闻资讯~~~

  离线 

TA的专栏

等级头衔

等級:晓枫资讯-列兵

在线时间
0 小时

积分成就
威望
0
贡献
0
主题
0
精华
0
金钱
16
积分
12
注册时间
2022-12-27
最后登录
2022-12-27

发表于 2024-8-29 09:25:17 | 显示全部楼层
路过,支持一下
http://bbs.yzwlo.com 晓枫资讯--游戏IT新闻资讯~~~

  离线 

TA的专栏

等级头衔

等級:晓枫资讯-列兵

在线时间
0 小时

积分成就
威望
0
贡献
0
主题
0
精华
0
金钱
19
积分
18
注册时间
2022-12-24
最后登录
2022-12-24

发表于 2024-10-30 17:24:04 | 显示全部楼层
顶顶更健康!!!
http://bbs.yzwlo.com 晓枫资讯--游戏IT新闻资讯~~~

  离线 

TA的专栏

  • 打卡等级:无名新人
  • 打卡总天数:1
  • 打卡月天数:0
  • 打卡总奖励:10
  • 最近打卡:2024-10-01 22:31:28
等级头衔

等級:晓枫资讯-列兵

在线时间
0 小时

积分成就
威望
0
贡献
0
主题
0
精华
0
金钱
22
积分
4
注册时间
2024-1-15
最后登录
2024-10-1

发表于 前天 17:06 | 显示全部楼层
感谢楼主分享。
http://bbs.yzwlo.com 晓枫资讯--游戏IT新闻资讯~~~
严禁发布广告,淫秽、色情、赌博、暴力、凶杀、恐怖、间谍及其他违反国家法律法规的内容。!晓枫资讯-社区
您需要登录后才可以回帖 登录 | 立即注册

本版积分规则

1楼
2楼
3楼
4楼

手机版|晓枫资讯--科技资讯社区 本站已运行

CopyRight © 2022-2025 晓枫资讯--科技资讯社区 ( BBS.yzwlo.com ) . All Rights Reserved .

晓枫资讯--科技资讯社区

本站内容由用户自主分享和转载自互联网,转载目的在于传递更多信息,并不代表本网赞同其观点和对其真实性负责。

如有侵权、违反国家法律政策行为,请联系我们,我们会第一时间及时清除和处理! 举报反馈邮箱:点击这里给我发消息

Powered by Discuz! X3.5

快速回复 返回顶部 返回列表