多线程-定时器

目录

1.定时器是什么

2.标准库中的定时器

 3.实现定时器

3.1 MyTimer类

  1.首先Timer 类提供的核⼼接⼝为 schedule, ⽤于注册⼀个任务, 并指定这个任务多⻓时间后执⾏.

   2.Timer 实例中, 通过 PriorityQueue 来组织若⼲个 Task 对象. 通过 schedule 来往队列中插⼊⼀个个 Task 对象.

3.Timer 类中存在⼀个 worker 线程, ⼀直不停的扫描队⾸元素, 看看是否能执⾏这个任务.

 3.2MyTimerTask类

3.3main类


1.定时器是什么

       定时器也是软件开发中的⼀个重要组件. 类似于⼀个 "闹钟". 达到⼀个设定的时间之后, 就执⾏某个指定好的代码. 定时器是⼀种实际开发中⾮常常⽤的组件. ⽐如⽹络通信中, 如果对⽅ 500ms 内没有返回数据, 则断开连接尝试重连. ⽐如⼀个 Map, 希望⾥⾯的某个 key 在 3s 之后过期(⾃动删除). 类似于这样的场景就需要⽤到定时器.

2.标准库中的定时器

标准库中提供了⼀个 Timer 类. Timer 类的核⼼⽅法为 schedule .

schedule 包含两个参数. 第⼀个参数指定即将要执⾏的任务代码, 第⼆个参数delay指定多⻓时间之后 执⾏ (单位为毫秒)

MyTimer timer = new MyTimer();
    timer.schedule(new Runnable() {
        @Override
        public void run() {
            System.out.println("hello 3000");
        }
    },3000);

 3.实现定时器

定时器的构成
⼀个带优先级队列(不要使⽤ PriorityBlockingQueue, 容易死锁!)
队列中的每个元素是⼀个 Task 对象.
Task 中带有⼀个时间属性, 队⾸元素就是即将要执⾏的任务
同时有⼀个 worker 线程⼀直扫描队⾸元素, 看队⾸元素是否需要执⾏

3.1 MyTimer类

  1.首先Timer 类提供的核⼼接⼝为 schedule, ⽤于注册⼀个任务, 并指定这个任务多⻓时间后执⾏.

      
public void schedule(Runnable runnable , long delay){
         synchronized (locker){
            MyTimerTask task = new MyTimerTask(runnable, delay);
            queue.offer(task);//用于将指定元素插入到队列尾部,如果队列已满则返回 false
            //添加新元素后,唤醒扫描线程的wait
            locker.notify();
        }
    MyTimerTask task = new MyTimerTask(runnable, delay);创建了一个MyTimerTask
对象,用于表示一个任务。它接受两个参数:runnable和delay。

         参数runnable:是一个Runnable对象,表示要执行的具体任务逻辑。你可以通过实现Runnable接口并重写run()方法来定义自己的任务逻辑。

        参数delay:是一个long类型的值,表示任务的延迟时间。它指定了从当前时间开始,到任务执行时间的时间间隔(以毫秒为单位)。在构造MyTimerTask对象时,会根据当前时间和延迟时间计算出任务的绝对执行时间,并保存在time成员变量中。

   2.Timer 实例中, 通过 PriorityQueue 来组织若⼲个 Task 对象. 通过 schedule 来往队列中插⼊⼀个个 Task 对象.

//负责扫描任务队列,执行任务的线程。
    private Thread t = null;
    // 任务队列
    private PriorityQueue<MyTimerTask> queue = new PriorityQueue<>();
    //弄一个锁对象
    public Object locker = new Object();

     public void schedule(Runnable runnable , long delay){
         synchronized (locker){
            MyTimerTask task = new MyTimerTask(runnable, delay);
            queue.offer(task);//用于将指定元素插入到队列尾部,如果队列已满则返回 false
            //添加新元素后,唤醒扫描线程的wait
            locker.notify();
        }

    }

   PriorityQueue:是Java集合框架中的一个实现了优先级队列的类。它可以用于存储元素,并按照一定的优先级来访问和删除元素。

     同时我们为了线程的安全性,创建了一个锁对象。

3.Timer 类中存在⼀个 worker 线程, ⼀直不停的扫描队⾸元素, 看看是否能执⾏这个任务.

      

public MyTimer(){
         t = new Thread(()->{
            //扫描线程就需要循环的反复的扫描队首元素,然后判定队首元素是不是时间到了
            //如果没有到,啥也不干
            //如果到了,就执行这个任务并且把这个任务从队列中删除掉。
            while (true){
                try {
                synchronized (locker){
                    if(queue.isEmpty()){
                        //暂不处理
                            locker.wait();
                    }
                    MyTimerTask task = queue.peek();
                    //获取到当前时间
                    long curTime = System.currentTimeMillis();
                    if(curTime >= task.getTime()){
                        //当前时间已经到了任务时间,就可以执行任务了
                        queue.poll();//从队列中获取队头元素,并将其从队列中移除。
                        task.run();
                    }else {
                        //当前时间还没有到,暂时先不执行
                        //continue;//“忙等”,没有意义,应该把cpu资源让出来
                        //Thread.sleep 不能用sleep会错过新的任务
                        locker.wait(task.getTime() - curTime);
                    }
                }//解锁
                     } catch (InterruptedException e) {
                    e.printStackTrace();
                }
            }
         });
         t.start();
    }

     如果队列为空的话我们就暂时不出力,用wait 等待一下。我们用curtime来接受当前的时间。

 3.2MyTimerTask类

       Task 类⽤于描述⼀个任务(作为 Timer 的内部类). ⾥⾯包含⼀个 Runnable 对象和⼀个 time(毫秒时间戳) 这个对象需要放到 优先队列 中. 因此需要实现 Comparable 接⼝.
class MyTimerTask  implements Comparable<MyTimerTask>{
    //在什么时间点来执行这个任务
    //此约定这个 time 是一个 ms 级别的时间戳
    private long time;
    //实际任务要执行的代码
    private Runnable runnable;

    public  long getTime(){
        return time;
    }
    public MyTimerTask(Runnable runnable , long delay){
        this.runnable = runnable;
        //计算一下真正要执行任务的绝对时间(使用绝对时间,方便判定任务是否到达时间的)
        this.time = System.currentTimeMillis() + delay;
    }
    public void run(){
        runnable.run();
    }

    @Override
    public int compareTo(MyTimerTask o) {
        return  (int) (this.time - o.time);
        //return (int)(o.time - this.time);//试一试是哪一个减哪一个
    }
}

       private Runnable runnable:

       我们将传入的runnable参数保存到成员变量runnable中。当任务到达执行时间时,定时器会调用MyTimerTask对象的run()方法来执行具体的任务逻辑,而run()方法实际上就是调用runnable对象的run()方法。这样一来,我们就可以通过传入不同的Runnable对象来定义不同的任务逻辑。

      this.time = System.currentTimeMillis() + delay;

     System.currentTimeMillis() 返回当前系统时间的毫秒表示,表示从1970年1月1日00:00:00 GMT开始到现在的时间间隔。delay 是任务的延迟时间,以毫秒为单位。通过将当前系统时间和延迟时间相加,我们可以得到任务的绝对执行时间。

3.3main类

public class ThreadDemo25 {
    public static void main(String[] args) {
    MyTimer timer = new MyTimer();
    timer.schedule(new Runnable() {
        @Override
        public void run() {
            System.out.println("hello 3000");
        }
    },3000);
        timer.schedule(new Runnable() {
            @Override
            public void run() {
                System.out.println("hello 2000");
            }
        },2000);
        timer.schedule(new Runnable() {
            @Override
            public void run() {
                System.out.println("hello 5000");
            }
        },5000);
        System.out.println("hello main");
    }
}

       首先创建了一个 MyTimer 对象 timer。然后,通过调用 timer.schedule() 方法来添加三个任务。每个任务都是通过匿名内部类实现的 Runnable 接口,并重写了 run() 方法在 run() 方法中,分别打印出不同的消息,表示任务的内容。每个任务都具有不同的延迟时间:3000毫秒、2000毫秒和5000毫秒。这意味着第一个任务将在程序启动后的3秒钟之后执行,第二个任务将在2秒钟之后执行,第三个任务将在5秒钟之后执行。

                                                          希望大家多多支持!!! 

  • 10
    点赞
  • 30
    收藏
    觉得还不错? 一键收藏
  • 打赏
    打赏
  • 0
    评论
在Python中,多线程结合定时器通常用于执行周期性的任务或需要在特定时间间隔后响应的场景。Python提供了`threading`模块来支持多线程,并且`schedule`或者`APScheduler`这样的库可以方便地实现定时任务。 1. **多线程**:`threading`模块中的`Thread`类可以用来创建新的线程,每个线程有自己的独立执行路径。当你想在程序中并发执行多个任务时,可以为每个任务创建一个新的线程。 ```python import threading def task_to_run(): # 这里写你的任务代码 pass # 创建一个线程 thread = threading.Thread(target=task_to_run) # 启动线程 thread.start() ``` 2. **定时器**:`schedule`库允许你按照固定时间间隔调度函数的执行。例如: ```python from schedule import every, run_pending import time def job_function(): print("Job executed at", time.ctime()) every(5).seconds.do(job_function) # 每5秒执行一次job_function while True: run_pending() time.sleep(1) # 程序睡眠1秒,等待下一次调度 ``` 如果你想要更高级的定时任务功能,比如支持复杂的调度规则,可以使用`APScheduler`: ```python from apscheduler.schedulers.background import BackgroundScheduler scheduler = BackgroundScheduler() def job_function(): print("Job executed at", time.ctime()) scheduler.add_job(job_function, 'interval', seconds=5) # 每5秒执行一次 scheduler.start() # 开始调度 # 在程序结束前保持调度运行 while True: time.sleep(1) ```

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包

打赏作者

所遇皆随风

你的鼓励将是我创作的最大动力

¥1 ¥2 ¥4 ¥6 ¥10 ¥20
扫码支付:¥1
获取中
扫码支付

您的余额不足,请更换扫码支付或充值

打赏作者

实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值