定时器组件

目录

1.定时器是什么

2.标椎库中定时器

3.实现定时器


序列:多线程 - 010

1.定时器是什么

定时器是软件开发中的一个重要的组件,类似于一个“闹钟”。

一旦定时器达到一个设定的时间之后,就执行某个指定好的代码。

定时器组件_第1张图片

定时器是日常开发中非常常用的组件,比如网络通信中对方5秒内没有返回数据,则尝试重新连接。类似于这个场景,就需要使用到定时器。

2.标椎库中定时器

标椎库中提供了一个Timer类,Timer类的核心的方法为schedule()。

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

标椎库中定时器使用如下:

        Timer timer = new Timer();
        timer.schedule(new TimerTask() {//此处使用匿名内部类的写法,继承了TimerTask并且创建出一个实例
            @Override
            public void run() {//重写run方法,通过run方法来描述任务的详细情况
                System.out.println("这里是2000毫秒后的执行代码...");
            }
        },2000);//2000毫秒之后再执行该代码

3.实现定时器

定时器的构成:

  • 一个带优先级队列;
  • 队列中每一个元素是一个Task对象;
  • Task中带有一个时间属性,队首元素就是即将要执行的元素;
  • 同时有一个worker线程一直扫描队首元素,看队首元素是否要执行;

 定时器具体实现方法如下:

/**
 * 定时器-使用一个优先级队列的数据结构存放定时器对象
 */
class MyTimerTask implements Comparable{//实现Comparable接口,对相对时间进行排序
    private Runnable runnable;//要有一个执行的任务

    private long time;//还要有一个执行任务的时间

    //此处的delay就是schedule方法传入的“相对时间”
    public MyTimerTask(Runnable runnable,long delay){//创建一个构造方法
        this.runnable =runnable;
        this.time = System.currentTimeMillis() + delay;//当前时间加相对时间
    }
    @Override
    public int compareTo(MyTimerTask o) {//对于优先级队列来说,要求里边的元素务必是可比较的
        //这样的写法,就是让队首元素是最小时间的值
        return (int) (this.time - o.time);
        //如果是想让队首元素最大时间的值
        //return o.time - this.time;
    }
    public long getTime(){//获取执行任务的时间
        return time;
    }
    public Runnable getRunnable(){//获取线程对象
        return runnable;
    }
}

class MyTimer{//定时器数据结构类,用来存储定时器
    //使用一个数据结构,保存所有要安排的任务
    private PriorityQueue queue = new PriorityQueue<>();//创建队列,队列中存放MyTimerTask类对象元素
    private Object object = new Object();//使用这个对象作为锁对象

    public void schedule(Runnable runnable,long delay){//将定时器对象放入优先级队列中
        synchronized (object){//操作线程,需要加锁
            queue.offer(new MyTimerTask(runnable, delay));
            object.notify();//向队列里添加元素之后,就要唤醒扫描队列时为空的wait等待
        }
    }
    //搞一个扫描线程
    public MyTimer(){//构造方法,
        Thread thread = new Thread(()->{
            //扫描线程,就是需要不断地扫描队首元素,看是否到达时间
            while (true){
                synchronized (object){
                    //尽量不要使用if作为wait的判定条件
                    //使用while的目的是为了在wait被唤醒的时候,再次确认以下条件
                    while (queue.isEmpty()) {//队列为空时,等待队列中进入元素
                        try {
                            //这里的wait需要其他的线程唤醒
                            //添加了新的任务就应该唤醒
                            object.wait();
                        } catch (InterruptedException e) {
                            throw new RuntimeException(e);
                        }
                    }
                    MyTimerTask task = queue.peek();//队列非空,进行扫描队首元素
                    //比较一下,当前的队首元素是否可以执行了
                    long curTime = System.currentTimeMillis();//当前时间
                    if (curTime >= task.getTime()){
                        //当前时间已经到达了任务时间,就可以开始执行任务了
                        task.getRunnable().run();//执行任务
                        queue.poll();//执行后将任务给删除掉
                    }else {
                        //当前时间还没有到任务时间,暂时不执行
                        //暂时啥也不用干
                        try {
                            object.wait(task.getTime() - curTime);
                        } catch (InterruptedException e) {
                            throw new RuntimeException(e);
                        }
                    }
                }
            }
        });
        thread.start();
    }
}

public class Demo02 {//测试类
    public static void main(String[] args) {
        MyTimer timer = new MyTimer();//创建MyTimer类实例,此时开始timer对象就会开始不断扫描队列,运行时间到达的线程
        timer.schedule(new Runnable() {
            @Override
            public void run() {
                System.out.println("3000");
            }
        }, 3000);
        timer.schedule(new Runnable() {
            @Override
            public void run() {
                System.out.println("2000");
            }
        }, 2000);
        System.out.println("ZZZ...");
    }
}

上述代码的运行结果如下:

“ZZZ...”直接打印,“2000”在两秒之后打印,“3000”在三秒之后打印。

定时器组件_第2张图片

 

你可能感兴趣的:(JavaEE,(初阶),java,开发语言,java-ee)