JavaWeb——多线程中的定时器

概念

多线程编程中的重要组件,好比一个闹钟,有的逻辑不想立刻执行,而是要等一段时间之后再执行。
在网络编程中特别常见
在这里插入图片描述

实现

定时器的构成

1、使用一个Task类来描述一段逻辑(一个要执行的任务),同时也要记录这个任务在什么时候执行
在这里插入图片描述
2、使用一个阻塞优先队列(既支持阻塞特性,又支持按优先级的先进先出,本质上是一个堆)来组织若干个Task,使用优先队列是为了保证队首元素就是最早要被执行的任务。判断当前队列中是否有任务时间到了,需要执行,只需要判定队首元素是否到时间即可。
在这里插入图片描述
3、需要一个扫描线程,扫描线程要循环的检测队首元素是否需要执行,如果需要执行就进行执行。
在这里插入图片描述
4、提供一个方法,让调用者把任务安排到队列中
在这里插入图片描述
在这里插入图片描述
在这里插入图片描述
或者
在这里插入图片描述
在这里插入图片描述
总览
在这里插入图片描述

忙等优化

在扫描线程中会存在忙等,频繁扫描,查看时间,浪费CPU资源。
在这里插入图片描述
使用wait/notify解决
wait(time),有上限的等待,如果有notify就会被提前唤醒,如果没有notify,就会到达时间后自动唤醒。
在这里插入图片描述
扫描线程内部加上wait,大大降低了循环的执行次数
在这里插入图片描述

保证shedule中的mailBox和线程中的mailBox是一个对象,在构造方法中传入,安排方法中内部加入notify。
在这里插入图片描述

代码

在这里插入图片描述


import java.util.concurrent.PriorityBlockingQueue;

public  class ThreadDemo1 {
    //优先队列中的元素必须是可比较的
    //比较规则的指定主题是两种方式
    //1、让Task实现Compare接口
    //2、让优先队列构造的时候,传入一个比较器对象(Compareor)
    static class Task implements Comparable<Task> {
        //Runnable 中有一个run方法,就可以借助这个run方法来描述要执行的具体任务
        private Runnable command;
        //time表示啥时候来执行command,是一个绝对时间(ms级别的时间戳)
        private long time;

        //构造方法的参数表示:多少毫秒之后执行(表示的是一个相对时间)相对时间参数是为了使用方便
        public Task(Runnable command,long after){
            this.command = command;
            this.time = System.currentTimeMillis() + after;
        }

        //执行任务的具体逻辑
        public void run() {
            command.run();
        }
        @Override
        public int compareTo(Task o){
            //哪个时间小(先执行)
            return (int)(this.time - o.time);

        }
    }
    //扫描线程
    static class Worker extends Thread {
        private PriorityBlockingQueue<Task> queue = null;
        private Object mailBox = null;
        public Worker(PriorityBlockingQueue<Task> queue,Object mailBox){
            this.queue = queue;
            this.mailBox = mailBox;
        }

        public void run(){
            //实现具体的线程执行的内容
            while (true){
                try{
                    //1、取出队首元素,检查时间是否到了
                    Task task = queue.take();
                    //2、检查当前任务时间是否到了
                    long curTime = System.currentTimeMillis();//当前时间
                    if(task.time > curTime){
                        //时间还没到,就把任务再放回队列
                        queue.put(task);
                        synchronized (mailBox){
                            mailBox.wait(task.time - curTime);//等待的时间
                        }
                    }else {//时间到,直接执行
                        task.run();
                    }
                } catch (InterruptedException e) {//出现异常,直接break终止
                    e.printStackTrace();
                    break;
                }
            }
        }
    }
    static class Timer{
        //为了避免忙等需要使用wait方法
        //使用一个单独的对象辅助进行wait
        private Object mailBox = new Object();
        //定时器的基本构成,有三个部分
        //1、用一个类来描述任务
        //2、用一个阻塞优先队列来组织若干个任务,让队首元素是最早时间的任务
        //如果队首元素时间未到,那么其他的元素也肯定不能执行
        private PriorityBlockingQueue<Task> queue = new PriorityBlockingQueue<>();
        //3、用一个线程来循环扫描当前的阻塞队列的队首元素,如果时间到,就执行指定任务
        public Timer() {
            //构造线程
            Worker worker = new Worker(queue,mailBox);
            worker.start();

        }
        //4、提供一个方法,让调用者把任务安排
        // schedule 安排
        public void schedule(Runnable command,long after){
            Task task = new Task(command, after);
            queue.put(task);
            synchronized (mailBox){
                mailBox.notify();
            }
        }
    }

    public static void main(String[] args) {
        Timer timer = new Timer();
        timer.schedule(new Runnable() {
            @Override
            public void run() {
                System.out.println("hehe");
                timer.schedule(this,2000);//每隔两秒出现一个hehe
            }
        },5000);
    }
}

  • 0
    点赞
  • 1
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值