教你实现多线程案例定时器

目录

什么是定时器???

定时器的特点

手动实现一个定时器

定时器工作原理

定时器实现解析


什么是定时器???

当我们在做计划的时候,有事就会定个闹钟或者利用待办事项来提醒你要做这件事了,并且哪件事安排的时间最早就先执行谁.而我们软件开发中的定时器也是一样的--------需要我们安排任务并且记录多长时间后执行此任务.

在Java标准库中定时器是利用Timer类,通过调用timer类的schedule方法来表示多长时间后执行什么任务.

教你实现多线程案例定时器_第1张图片

教你实现多线程案例定时器_第2张图片 

  •  schedule方法第一个参数是表示要执行的任务(TimerTask类这个类实现了Runnable接口),第二个参数表示多长时间后执行

定时器的特点

  • 当我们使用定时器执行完任务时,程序不终止,因为定时器内部实现是利用多线程,内部还有线程在工作
  • 在使用定时器执行任务时,进行等待期间,不影响其他线程执行任务.
  • 定时器可以执行多个任务

手动实现一个定时器

定时器工作原理

  • 由于定时器可以执行多个任务,并且每个任务的执行时间可能不同,我们就需要为时间更早的优先执行,所以使用优先级阻塞队列(PriorityBlockingQueue)来保证线程安全,同时为任务执行顺序安排优先级.
  • 定时器类内部有核心方法schedule(),该方法表示要执行的任务以及多长时间后执行.
  • 由于有多个任务,我们要实现一个任务类来描述每个任务(任务里包括时间,以及要做什么任务)
  • 时间更早的任务先执行,时间晚的任务后执行,当插入的任务比队列中首任务时间短时就立即执行,当插入任务比队首元素时间长时,将其放回队列中进行等待.

定时器实现解析

  • 准备任务类

教你实现多线程案例定时器_第3张图片

该任务类描述任务都要做什么,多长时间后执行此任务

  • 注意点: 初始化时间时,一定要使用绝对时间戳(也就是具体时间比如20220805XX时XX分我要做啥任务)
  • 使用优先级队列要重写comparable接口

  • Mytimer类内部构成

教你实现多线程案例定时器_第4张图片

  •  使用线程来执行任务

教你实现多线程案例定时器_第5张图片

  •  注意当队列为空时要使用wait等待,防止当插入任务时进行通知获取不到锁,就导致死锁问题
  • 使用synchronized保证线程安全,将整个操作打包成原子,防止在插入和等待时间又有任务插入,导致有时可能超时等待.
  • 当前任务时间早于或等于队首任务,立即执行,否则需要重新放回队列中,再次等待时间差的时间
  • 等使用wait等待时,同时在插入任务时,也要使用notify进行通知

代码实现:

//任务 : 任务是干啥的  需要多长时间
class MyTask implements Comparable{
    private long time;//任务时长
    private Runnable command;//要做的任务

    public MyTask(Runnable command,long after){
        this.time= after+ System.currentTimeMillis();
        this.command = command;
    }

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

    public long getTime(){
        return this.time ;
    }


    @Override
    public int compareTo(MyTask o) {
        return (int) (this.time - o.time);
    }
}
public class MyTimer {
    //实现一个定时器

    //线程安全的优先级队列 --将存放的任务按照时间的优先级存放
    private PriorityBlockingQueue queue = new PriorityBlockingQueue<>();
    //设置锁对象
    public Object locker = new Object();
    private void schedule(Runnable command,long after){
        MyTask task = new MyTask(command,after);
        synchronized (locker){
            queue.put(task);
            locker.notify();
        }
    }
    //准备一个线程进行执行
    public MyTimer(){
        Thread t = new Thread(()->{
           while(true){
               try {
                   //这里加锁是为了将其下面的操作打包为一个整体
                   //防止容易出现在将任务放入队列中和等待之间又有任务加进来
                   //导致出现等待时间过长
                    synchronized (locker) {
                        while (queue.isEmpty()) {
                            //判断是否为空防止一开没有任务就弹出,就容易死锁
                            //这里要wait释放锁,防止notify一直等不到锁
                            locker.wait();
                        }
                        MyTask e = queue.take();
                        long curTime = System.currentTimeMillis();//当前时间
                        if (e.getTime() > curTime) {
                            //如果弹出的任务时间还没有到当前时间,再次把它放入队列中
                            //然后进行等待x.getTime - curTime
                            queue.put(e);
                            locker.wait(e.getTime()-curTime);
                        }else {
                            //时间到了立马执行
                            e.run();
                        }
                    }
               } catch (InterruptedException e) {
                   e.printStackTrace();
               }
           }
        });
        t.start();
    }
    
    //for test
    public static void main2(String[] args) {
        MyTimer timer = new MyTimer();
        timer.schedule(new Runnable() {
            @Override
            public void run() {
                System.out.println("我是");
            }
        },2000);
        timer.schedule(new Runnable() {
            @Override
            public void run() {
                System.out.println("小bit");
            }
        },3000);
        timer.schedule(new Runnable() {
            @Override
            public void run() {
                System.out.println("你好");
            }
        },1000);
    }
   //for test
    public static void main(String[] args) {
        MyTimer timer = new MyTimer();
        for(int i =0;i<10;++i){
            timer.schedule(new Runnable() {
                @Override
                public void run() {
                    System.out.println("hello");
                }
            },1000);
        }
        System.out.println("其他任务");
    }
}

你可能感兴趣的:(JavaEE,java,jvm,开发语言)