当前位置:首页 » 《随便一记》 » 正文

定时器--JAVA

1 人参与  2024年02月08日 09:16  分类 : 《随便一记》  评论

点击全文阅读


定时器是软件开发中的一个重要组件,类似于一个"闹钟"当达到一个设定的时间之后,就执行某个指定好的代码(任务)。

Timer

JAVA标准库中已经为我们实现了一个定时器,我们直接new就行了。

Timer timer = new Timer();

Timer类中最重要的一个方法就是schedule(),这个方法用于设置定时器待执行的任务和执行任务的时间。

public static void main(String[] args) {    Timer timer = new Timer();    //在3秒后打印3000    timer.schedule(new TimerTask() {        @Override        public void run() {            System.out.println("3000");        }    }, 3000);    //在2秒后打印2000    timer.schedule(new TimerTask() {        @Override        public void run() {            System.out.println("2000");        }    }, 2000);    //在1秒后打印1000    timer.schedule(new TimerTask() {        @Override        public void run() {            System.out.println("1000");        }    }, 1000);        System.out.println("OK");}

可以发现在代码执行完毕后程序并没有结束,这是因为虽然主线程结束了但是Timer类中的线程在阻止程序结束,它们还在等待新的任务进来被执行。

为了可以更好的理解定时器的原理,下面进行简单的模拟实现。

模拟实现

首先我们需要先创建一个MyTimerTask类,该类主要用来保存待执行的任务,和执行该任务的时间点。

class MyTimerTask {    public Runnable runnable;    //存储绝对时间,后期直接和当前时间比较大小就行    public long time;    public MyTimerTask(Runnable runnable, long time){        this.runnable = runnable;        this.time = time + System.currentTimeMillis();    }}

接着写我们的定时器类MyTimer。首先我们应该先选择一种数据结构来存储所有的MyTimerTask,这里我推荐使用优先级队列,也就是堆。因为如果使用数组或链表来存储就需要你不断地遍历该数组/链表,而使用优先级队列就可以只检查队首元素是否到执行时间。

public class MyTimer {    private final PriorityQueue<MyTimerTask> priorityQueue = new PriorityQueue<>();}

因为我们使用了优先级队列所以我们需要让MyTimerTask类可以进行比较。

class MyTimerTask implements Comparable<MyTimerTask>{    ……    @Override    public int compareTo(MyTimerTask o) {        return (int) (this.time-o.time);    }}

接着我们需要实现一个schedule方法可以接收定时任务和时间,因为是多线程代码所以我们还应该加一个属性用来充当锁对象。

public class MyTimer {    private final PriorityQueue<MyTimerTask> priorityQueue = new PriorityQueue<>();    private Object lock = new Object();    public void schedule(Runnable runnable, long time) {        synchronized (lock) {            priorityQueue.add(new MyTimerTask(runnable, time));        }    }}

此时我们还需要一个自动检查队列的线程,而且该线程并不需要程序员来启动和创建,所以我们可以将它写在构造方法中。

public MyTimer() {    Thread t = new Thread(()->{        while(true) {            synchronized (lock) {                if (priorityQueue.isEmpty()) {                    //堆为空                           }                MyTimerTask myTimerTask = priorityQueue.peek();                if (myTimerTask.time <= System.currentTimeMillis()) {                    //执行当前任务                    myTimerTask.runnable.run();                    //将当前任务移除                    priorityQueue.poll();                }else {                    //时间没到                }            };        }    });    t.start();}

此处我们可以用阻塞队列的思想,当堆为空或者执行时间没到就使用wait()进行等待。有人添加任务时就使用notify()进行唤醒线程。

public class MyTimer {    private final PriorityQueue<MyTimerTask> priorityQueue = new PriorityQueue<>();    private Object lock = new Object();    public void schedule(Runnable runnable, long time) {        synchronized (lock) {            priorityQueue.add(new MyTimerTask(runnable, time));            lock.notify();        }    }    public MyTimer() {        Thread t = new Thread(()->{            while(true) {                synchronized (lock) {                    if (priorityQueue.isEmpty()) {                        //如果堆为空就阻塞等待                        try {                            lock.wait();                        } catch (InterruptedException e) {                            throw new RuntimeException(e);                        }                    }                    MyTimerTask myTimerTask = priorityQueue.peek();                    if (myTimerTask.time <= System.currentTimeMillis()) {                        //执行当前任务                        myTimerTask.runnable.run();                        priorityQueue.poll();                    }else {                        //时间没到就阻塞等待                        try {                            lock.wait(myTimerTask.time-System.currentTimeMillis());                        } catch (InterruptedException e) {                            throw new RuntimeException(e);                        }                    }                };            }        });        t.start();    }}

简单测试

public static void main(String[] args) {    MyTimer timer = new MyTimer();    //在3秒后打印3000    timer.schedule(()->{            System.out.println("3000");    }, 3000);    //在2秒后打印2000    timer.schedule(()->{            System.out.println("2000");    }, 2000);    //在1秒后打印1000    timer.schedule(()->{            System.out.println("1000");    }, 1000);    System.out.println("OK");}

完整代码

import java.util.PriorityQueue;class MyTimerTask implements Comparable<MyTimerTask>{    public Runnable runnable;    //存储绝对时间,后期直接和当前时间比较大小就行    public long time;    public MyTimerTask(Runnable runnable, long time){        this.runnable = runnable;        this.time = time + System.currentTimeMillis();    }    @Override    public int compareTo(MyTimerTask o) {        return (int) (this.time-o.time);    }}public class MyTimer {    private final PriorityQueue<MyTimerTask> priorityQueue = new PriorityQueue<>();    private Object lock = new Object();    public void schedule(Runnable runnable, long time) {        synchronized (lock) {            priorityQueue.add(new MyTimerTask(runnable, time));            lock.notify();        }    }    public MyTimer() {        Thread t = new Thread(()->{            while(true) {                synchronized (lock) {                    if (priorityQueue.isEmpty()) {                        //如果堆为空就阻塞等待                        try {                            lock.wait();                        } catch (InterruptedException e) {                            throw new RuntimeException(e);                        }                    }                    MyTimerTask myTimerTask = priorityQueue.peek();                    if (myTimerTask.time <= System.currentTimeMillis()) {                        //执行当前任务                        myTimerTask.runnable.run();                        priorityQueue.poll();                    }else {                        //时间没到就阻塞等待                        try {                            lock.wait(myTimerTask.time-System.currentTimeMillis());                        } catch (InterruptedException e) {                            throw new RuntimeException(e);                        }                    }                };            }        });        t.start();    }}


点击全文阅读


本文链接:http://zhangshiyu.com/post/67771.html

<< 上一篇 下一篇 >>

  • 评论(0)
  • 赞助本站

◎欢迎参与讨论,请在这里发表您的看法、交流您的观点。

关于我们 | 我要投稿 | 免责申明

Copyright © 2020-2022 ZhangShiYu.com Rights Reserved.豫ICP备2022013469号-1