当前位置:网站首页>Multi-threaded cases - timer

Multi-threaded cases - timer

2022-08-09 09:39:00 Living_Amethyst

定时器是什么

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

定时器是一种实际开发中非常常用的组件.
比如网络通信中, 如果对方 500ms 内没有返回数据, 则断开连接尝试重连.
比如一个 Map, 希望里面的某个 key 在 3s 之后过期(自动删除).
类似于这样的场景就需要用到定时器

标准库中的定时器

  • 标准库中提供了一个 Timer 类. Timer 类的核心方法为 schedule .
  • schedule 包含两个参数. 第一个参数指定即将要执行的任务代码, 第二个参数指定多长时间之后
    执行 (单位为毫秒).

示例:

public static void main(String[] args) {
    
        // java.util 里的一个组件
        Timer timer = new Timer();
        //schedule这个方法的效果 是 “安排一个任务”
        //不是立刻执行 而是3000毫秒之后执行
        timer.schedule(new TimerTask() {
    
            @Override
            public void run() {
    
                System.out.println("这是一个要执行的任务");
            }
        },3000);
    }

模拟实现定时器

很多细节的解析再注释中注明

//模拟实现 定时器

import java.util.PriorityQueue;
import java.util.concurrent.PriorityBlockingQueue;

class MyTask implements Comparable<MyTask>{
    
    //任务要干啥
    private Runnable command;
    //任务啥时候干
    private long time; //绝对时间

    public MyTask (Runnable command,long after){
    
        this.command = command;
        //此处记录的时间是一个绝对的时间戳,不是多长时间后执行
        this.time = System.currentTimeMillis()+after;
    }

    //执行任务的方法 直接在内部调用 Runnable 的 run 即可
    public void run(){
    
        command.run();
    }

    public long getTime() {
    
        return time;
    }

    @Override
    public int compareTo(MyTask o) {
    
        //希望时间小的在前 大的在后
        return (int) (this.time - o.time);
    }
}

class MyTimer {
    
    //用来阻塞等待的锁对象
    private Object locker = new Object();

    //使用优先级队列来保存若干个任务
    private PriorityBlockingQueue<MyTask> queue = new PriorityBlockingQueue<>();

    // command:要执行的任务是啥
    // after:多长时间之后执行这个任务
    public void  schedule(Runnable command,long after) {
    
        MyTask myTask = new MyTask(command,after);
        // 防止 新插入的任务 比之前队首的任务的时间还早,需要唤醒
        synchronized (locker){
    
            queue.put(myTask);  //把加入操作也加锁
            locker.notify();
        }
    }

    public MyTimer(){
    
        // 启动一个线程
        Thread t = new Thread(()->{
    
           while (true){
    
               //循环过程中 不断尝试从队列中获取到队首元素
               //判定队首元素当时的时间是否就绪,就绪了就执行 不就绪就不执行
               try {
    
                   synchronized (locker) {
    
                       MyTask myTask = queue.take();//取的是队首元素,时间最早的任务
                       long curTime = System.currentTimeMillis();
                       if (myTask.getTime() > curTime) {
    
                           //时间还没到
                           queue.put(myTask); //把任务再放回队列
                           //队首的(最早执行的)元素时间还没到,需要等待,不然一直循环 CPU空转 内耗
                           locker.wait(myTask.getTime() - curTime);
                       } else {
    
                           //时间到了 执行任务
                           myTask.run();
                       }
                   }

               } catch (InterruptedException e) {
    
                   e.printStackTrace();
               }

           }
        });
        t.start();
    }
}
public class Demo18 {
    
    public static void main(String[] args) {
    
        MyTimer myTimer = new MyTimer();
        myTimer.schedule(new Runnable() {
    
            @Override
            public void run() {
    
                System.out.println("111");
            }
        },2000);

        myTimer.schedule(new Runnable() {
    
            @Override
            public void run() {
    
                System.out.println("222");
            }
        },4000);

        myTimer.schedule(new Runnable() {
    
            @Override
            public void run() {
    
                System.out.println("333");
            }
        },6000);
    }
}
原网站

版权声明
本文为[Living_Amethyst]所创,转载请带上原文链接,感谢
https://yzsam.com/2022/221/202208090934331707.html