IT数码 购物 网址 头条 软件 日历 阅读 图书馆
TxT小说阅读器
↓语音阅读,小说下载,古典文学↓
图片批量下载器
↓批量下载图片,美女图库↓
图片自动播放器
↓图片自动播放器↓
一键清除垃圾
↓轻轻一点,清除系统垃圾↓
开发: C++知识库 Java知识库 JavaScript Python PHP知识库 人工智能 区块链 大数据 移动开发 嵌入式 开发工具 数据结构与算法 开发测试 游戏开发 网络协议 系统运维
教程: HTML教程 CSS教程 JavaScript教程 Go语言教程 JQuery教程 VUE教程 VUE3教程 Bootstrap教程 SQL数据库教程 C语言教程 C++教程 Java教程 Python教程 Python3教程 C#教程
数码: 电脑 笔记本 显卡 显示器 固态硬盘 硬盘 耳机 手机 iphone vivo oppo 小米 华为 单反 装机 图拉丁
 
   -> Java知识库 -> 【多线程案例】定时器 -> 正文阅读

[Java知识库]【多线程案例】定时器

1. 定时器

1.1 定时器定义

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

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

1.1 标准库中的定时器

  • 标准库中提供了一个 Timer 类. Timer 类的核心方法为 schedule .
  • schedule 包含两个参数. 第一个参数指定即将要执行的任务代码, 第二个参数指定多长时间之后
    执行 (单位为毫秒).
 public static void main(String[] args) {
        Timer timer=new Timer();
        timer.schedule(new TimerTask() {
            @Override
            public void run() {
                System.out.println("hello timer");
            }
        },3000);

        System.out.println("main");
    }

在这里插入图片描述

1.2 定时器的模拟实现

定时器的构成:

  • 一个带优先级的阻塞队列 (PriorityBlockingQueue
    带优先级的原因:
    因为阻塞队列中的任务都有各自的执行时刻 (delay). 最先执行的任务一定是 delay 最小的. 使用带
    优先级的队列就可以高效的把这个 delay 最小的任务找出来.

  • 队列中的每个元素是一个 Task 对象.

  • Task 中带有一个时间属性, 队首元素就是即将执行的任务

  • 同时有一个 t 线程一直扫描队首元素, 看队首元素是否需要执行

  1. Timer 类提供的核心接口为 schedule, 用于注册一个任务, 并指定这个任务多长时间后执行.

  2. Task 类用于描述一个任务(作为 Timer 的内部类). 里面包含一个 Runnable 对象和一个 time(毫秒时
    间戳)
    这个对象需要放到 优先队列 中. 因此需要实现 Comparable 接口.

  3. Timer 实例中, 通过 PriorityBlockingQueue 来组织若干个 Task 对象.
    通过 schedule 来往队列中插入一个个 Task 对象

  4. Timer 类中存在一个 t 线程, 一直不停的扫描队首元素, 看看是否能执行这个任务. (所谓 “能执行” 指的是该任务设定的时间已经到达了. )

完整代码(需要注意的点在代码中以注释形式给出,包含测试main代码)

import java.util.concurrent.PriorityBlockingQueue;

/**
 * 定时器的构成:
 * 一个带优先级的阻塞队列
 * 队列中的每个元素是一个 Task 对象.
 * Task 中带有一个时间属性, 队首元素就是即将执行的任务
 * 同时有一个 t 线程一直扫描队首元素, 看队首元素是否需要执行
 */

//创建一个类,表示一个任务
class MyTask implements Comparable<MyTask>{
    //任务具体要干啥
    private Runnable runnable;
    //任务具体啥时候干,保存任务要执行的毫秒级时间戳
    private long time;

    //after是一个时间间隔,不是绝对的时间的时间戳值
    public MyTask(Runnable runnable,long delay){
        this.runnable=runnable;
        this.time=System.currentTimeMillis()+delay;
    }

    public void run(){
        runnable.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<>();

    public void schedule(Runnable runnable,long delay){
        MyTask task=new MyTask(runnable,delay);
        queue.put(task);
        //每次任务插入成功之后, 都唤醒一下扫描线程, 让线程重新检查一下队首的任务看是否时间到要执行
        synchronized (locker){
            locker.notify();
        }
    }

    public MyTimer(){
        Thread t=new Thread(()->{
            while (true){
                try {
                    //先取队首元素
                    MyTask task=queue.take();
                    //再比较一下看看当前这个任务时间到了没
                    long curTime=System.currentTimeMillis();
                    if (curTime<task.getTime()){
                        //时间没到,再把任务塞回队列中
                        queue.put(task);
                        //指定等待时间,防止“忙等”,消耗不必要的CPU资源
                        //指定一个等待时间
                        synchronized (locker){
                            locker.wait(task.getTime()-curTime);
                        }
                    }else {
                        //时间到了,执行这个任务
                        task.run();
                    }
                } catch (InterruptedException e) {
                    e.printStackTrace();
                }
            }
        });
        t.start();
    }
}

public class Demo12 {
    public static void main(String[] args) {
        MyTimer myTimer=new MyTimer();
        myTimer.schedule(new Runnable() {
            @Override
            public void run() {
                System.out.println("hello timer");
            }
        },3000);
        System.out.println("main");
    }
}

在这里插入图片描述

  • over~
  Java知识库 最新文章
计算距离春节还有多长时间
系统开发系列 之WebService(spring框架+ma
springBoot+Cache(自定义有效时间配置)
SpringBoot整合mybatis实现增删改查、分页查
spring教程
SpringBoot+Vue实现美食交流网站的设计与实
虚拟机内存结构以及虚拟机中销毁和新建对象
SpringMVC---原理
小李同学: Java如何按多个字段分组
打印票据--java
上一篇文章      下一篇文章      查看所有文章
加:2022-04-09 18:09:53  更:2022-04-09 18:10:19 
 
开发: C++知识库 Java知识库 JavaScript Python PHP知识库 人工智能 区块链 大数据 移动开发 嵌入式 开发工具 数据结构与算法 开发测试 游戏开发 网络协议 系统运维
教程: HTML教程 CSS教程 JavaScript教程 Go语言教程 JQuery教程 VUE教程 VUE3教程 Bootstrap教程 SQL数据库教程 C语言教程 C++教程 Java教程 Python教程 Python3教程 C#教程
数码: 电脑 笔记本 显卡 显示器 固态硬盘 硬盘 耳机 手机 iphone vivo oppo 小米 华为 单反 装机 图拉丁

360图书馆 购物 三丰科技 阅读网 日历 万年历 2024年11日历 -2024/11/24 5:49:46-

图片自动播放器
↓图片自动播放器↓
TxT小说阅读器
↓语音阅读,小说下载,古典文学↓
一键清除垃圾
↓轻轻一点,清除系统垃圾↓
图片批量下载器
↓批量下载图片,美女图库↓
  网站联系: qq:121756557 email:121756557@qq.com  IT数码