【多线程基础】定时器

目录

一、定时器是什么

二、定时器的使用

三、自定义实现一个定时器


一、定时器是什么

        定时器是软件开发的一个重要组件,类似于一个“闹钟”,达到一个设定的时间之后,就执行某个指定好的代码。

二、定时器的使用

1、标准库中提供了一个Timer类,Timer类的核心方法为schedule;

2、schedule包含两个参数,第一个参数指定即将要执行的任务代码,第二个参数指定多长时间之后执行(单位为毫秒)

代码案例:

public class ThreadDemo15 {
    public static void main(String[] args) {
        Timer timer = new Timer();
        timer.schedule(new TimerTask() {
            @Override
            public void run() {
                System.out.println("hello4");
            }
        },4000);
        timer.schedule(new TimerTask() {
            @Override
            public void run() {
                System.out.println("hello3");
            }
        },3000);
        timer.schedule(new TimerTask() {
            @Override
            public void run() {
                System.out.println("hello2");
            }
        },2000);
        timer.schedule(new TimerTask() {
            @Override
            public void run() {
                System.out.println("hello1");
            }
        },1000);
        System.out.println("hello");
    }
}

测试结果:

三、自定义实现一个定时器

定时器的构成:

1、一个带优先级的阻塞队列

为什么要带优先级呢?

因为阻塞队列中的任务都有各自的执行时刻,最先执行的任务一定是delay最小的,使用带优先级队列这种数据结构就可以高效把这个delay最小的任务找出来。

2、队列中的每个元素是一个Task对象。

3、Task中带有一个时间属性,队首元素就是即将要执行的任务。

4、同时会有一个线程一直扫描队首元素,看队首元素是否需要执行。

1、首先构建一个MyTask类,表示一个任务

class MyTask implements Comparable<MyTask>{
    public Runnable runnable;
    public long time;

    public MyTask(Runnable runnable, long delay) {
        this.runnable = runnable;
        //取当前时刻的时间戳+delay,作为该任务实际执行的时间戳
        this.time = System.currentTimeMillis() + delay;
    }

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

2、实现一个定时器(内置一个扫描线程)

扫描线程的弊端:一直循环判断,占用系统的资源。(例如我们一个小时后去上课,但是在这一小时内我们反复进行看时间的工作,这样会消耗资源,这里也就是代码中频繁的出队列操作)。

解决办法:可以通过线程阻塞和唤醒来解决这种弊端。(例如如果有一个任务一个小时后进行,我们会让扫描线程wait一个小时,但是在此期间如果有新的任务需要执行,我们就可以采用notify来进行唤醒操作)

注意:这里的wait不能替换成sleep,因为sleep是指定一个线程休眠多长时间(例如如果有一个任务一个小时后进行,我们会让sleep休眠一个小时,但是在此如果有新的任务执行,我们以下休眠过头导致错过此任务)。

class MyTimer {
    //带优先级的阻塞队列
    private PriorityBlockingQueue<MyTask> queue = new PriorityBlockingQueue<>();
    Object locker = new Object();

    public void schedule(Runnable runnable, long delay) {
        //构造MyTask
        MyTask myTask = new MyTask(runnable, delay);
        queue.offer(myTask);
        synchronized (locker) {
            locker.notify();
        }
    }

    public MyTimer() {
        Thread t = new Thread(() -> {
            while (true) {
                try {
                    synchronized (locker) {
                        MyTask myTask = queue.take();
                        long curTime = System.currentTimeMillis();
                        if (myTask.time <= curTime) {
                            //时间到了可以执行任务
                            myTask.runnable.run();
                        } else {
                            //时间还没到
                            queue.offer(myTask);
                            locker.wait(myTask.time - curTime);
                        }
                    }
                } catch (InterruptedException e) {
                    e.printStackTrace();
                }
            }
        });
        t.start();
    }
}

测试代码:

public class ThreadDemo16 {
    public static void main(String[] args) {
        MyTimer myTimer = new MyTimer();
        myTimer.schedule(new Runnable() {
            @Override
            public void run() {
                System.out.println("hello4");
            }
        }, 4000);
        myTimer.schedule(new Runnable() {
            @Override
            public void run() {
                System.out.println("hello3");
            }
        }, 3000);
        myTimer.schedule(new Runnable() {
            @Override
            public void run() {
                System.out.println("hello2");
            }
        }, 2000);
        myTimer.schedule(new Runnable() {
            @Override
            public void run() {
                System.out.println("hello1");
            }
        }, 1000);
        System.out.println("hello");
    }
}

测试结果:

评论 1
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值