【多线程】定时器

目录

定时器

1. 定时器的概念 

2. 标准库中的定时器

3. 模拟定时器


定时器

1. 定时器的概念 

定时器是一种用于执行定时任务的工具,它可以设定一个任务在未来某个时刻运行,或者在固定时间间隔内重复执行

定时器在我们生活中用途非常广泛

用途1:在网上购物,用户下单后,30 分钟内未支付则自动取消订单

用途2:智能手表上面的心率检测,就是固定间隔一段时间进行心率检测,生成心率图


2. 标准库中的定时器

在java标准库中,常用Timer类和TimeTask类来实现定时器功能

 TimerTask类

用于表示可以由Timer调度执行的任务,通过重写run()方法让用户可以自定义任务

            TimerTask task = new TimerTask() {
                @Override
                public void run() {
                    System.out.println("111");
                }
            };

如上代码,通过重写run方法来自定义任务

注意:TimerTask类是一个抽象类 

Timer类

允许在指定延迟后执行任务或按固定时间间隔重复执行任务,这些功能依靠schedule( )方法实现

schedule( )方法核心作用:将任务添加到定时器的调度队列中并根据指定的延迟或周期参数安排任务的执行时间

可以认为是告诉定时器:“在某个时间点或周期,执行这个任务”

            timer.schedule(task,1000);

使用schedule()方法规定延迟的时间 

           timer.schedule(task,1000,3000);

 schedule(TimerTask task, long delay, long period)方法,第一次延迟1秒执行任务,后面每隔3秒执行一次(循环)


通过使用Timer类和TimeTask类来实现定时器功能

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

public class Demo_6 {
    public static void main(String[] args) {
        Thread thread = new Thread(()->{
            Timer timer = new Timer();

            TimerTask task = new TimerTask() {
                @Override
                public void run() {
                    System.out.println("111");
                }
            };

            TimerTask task1 = new TimerTask() {
                @Override
                public void run() {
                    System.out.println("222");
                }
            };

            TimerTask task2 = new TimerTask() {
                @Override
                public void run() {
                    System.out.println("333");
                }
            };

            timer.schedule(task,1000);
            timer.schedule(task1,2000);
            timer.schedule(task2,3000);

        });

        thread.start();

        System.out.println("任务开始");

    }
}

 

将所有的任务执行完后,定时器进入阻塞状态,当有新任务被添加进调度队列中,会被唤醒并执行任务


3. 模拟定时器

了解了定时器的功能,我们可以尝试着自己构建出一个定时器

整体方向

  • Timer类中使用优先级队列,队列中的元素都是TimerTask对象

使用优先级队列可以实现定时器优先使用延迟时间少的任务

  • 每一个TimerTask对象都带有一个时间属性,为了保证优先级,使用比较器给出比较依据
  • 实现只要队列里面有任务就会自动实现任务,一直处于运行状态,没有就会处于阻塞状态

可以将一个线程放在Timer的构造器(达到只要构建出Timer实例,就启动线程,那么就可以一直执行任务)

线程的功能:一直扫描队首元素, 看队首元素是否需要执行

为了实现阻塞功能,可以使用带有优先级的阻塞队列 


MyTimerTask类的构建

在TimerTask类中需要构建出比较器(根据时间可以将任务进行排序,时间少的先执行)

每个任务都需要实现代办事项和延迟时间(构造方法中添加Runable和时间参数)

class MyTimeTask implements Comparable<MyTimeTask> {
    private long time;
    private Runnable runnable;
    public MyTimeTask(Runnable runnable ,int delay){
        this.runnable = runnable;
        this.time = System.currentTimeMillis()+delay;
    }
    public long getTime(){
        return time;
    }

    @Override
    public int compareTo(MyTimeTask o) {
        return (int) (this.time-o.time);
    }

    public void run() {
        runnable.run();
    }
}

System.currentTimeMillis()+delay:当前时间+延迟时间,得到的是一个绝对时间(具体什么时间执行)

MyTimer类的构建

schedule方法

调用schedule方法,传入具体实现的功能和延迟时间

在方法中:1. 创建出一个任务  2. 将任务添加进优先级队列中  3. 实现唤醒功能

    PriorityQueue<MyTimeTask> queue = new PriorityQueue<>();

    Object lock = new Object();
    //提供添加任务方法
    public void schedule(Runnable runnable,int delay){
        synchronized (lock){
            MyTimeTask task = new MyTimeTask(runnable,delay);
            queue.offer(task);
            lock.notify();
        }
    }

 MyTimer构造方法

  • 当队列为空(没有任务),进入阻塞状态
  • 当队列不为空(有任务),取出队列元素,判断是否可以执行,时间到了则执行,时间没有到,则进入阻塞状态
  • 实现一直判断,在最外层套上while循环
    public MyTimer(){
        t = new Thread(()->{
            //一直扫描

                while (true) {
                    try {
                        synchronized (lock) {
                        //判断是否为空,为空,无法扫描
                        while (queue.isEmpty()) {//使用while,被唤醒后再次比较
//                        continue;//一直退出,然后在进来,容易导致线程饥饿问题
                            lock.wait();
                        }
                        //判断时间到了吗
                        MyTimeTask task = queue.peek();
                        long nowTime = System.currentTimeMillis();
                        //如果时间到了,那么就从队列中取出,并开始运行
                        if (nowTime >= task.getTime()) {
                            queue.poll();
                            task.run();
                        } else {
                            lock.wait(task.getTime()-nowTime);
                        }
                    }
                } catch (InterruptedException e) {
                        throw new RuntimeException(e);
                    }
                }
        });
        t.start();
    }

 出现了多个线程修改一个变量的情况,会出现线程安全问题(加锁)


 点赞的宝子今晚自动触发「躺赢锦鲤」buff! 

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

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

余额充值