<JavaEE> 经典设计模式之 -- 定时器

目录

一、定时器的概念

[二、Java 标准库中的定时器](#二、Java 标准库中的定时器)

三、实现自己的定时器


一、定时器的概念

|----------------------------------------------|
| 什么是定时器? |
| 定时器是软件开发中的一个常用且重要组件,作用是在达到设定时间后,执行指定的代码。 |


二、Java 标准库中的定时器

|---------------------------------------------------------------------|
| 1)Timer 类 |
| 在 Java 中,使用 Timer 类实现定时器的功能。Timer 类使用 schedule() 方法为定时器添加待执行任务。 |

|--------------------------------------------------------------|
| 2)schedule() 方法 |
| schedule() 方法需要两个参数,第一个参数是计划执行的任务代码,第二个参数是任务等待多少时间后开始执行。 |

++代码演示 Timer 类的使用:++

java 复制代码
public class Timer_Demo0 {
    public static void main(String[] args) {
        //新建定时器;
        Timer timer = new Timer();

        //设定任务为打印,等待3秒后执行;
        timer.schedule(new TimerTask() {
            @Override
            public void run() {
                System.out.println("3号举手");
            }
        },3000);

        //设定任务为打印,等待2秒后执行;
        timer.schedule(new TimerTask() {
            @Override
            public void run() {
                System.out.println("2号举手");
            }
        },2000);

        //设定任务为打印,等待1秒后执行;
        timer.schedule(new TimerTask() {
            @Override
            public void run() {
                System.out.println("1号举手");
            }
        },1000);
    }
}

//运行结果:
1号举手
2号举手
3号举手
...

程序没有结束运行。

|---------------------------------------------------|
| 3)为什么程序没有结束? |
| Timer 类中,内置的线程是一个前台线程,只要有一个前台线程未结束,程序就不会停止运行。 |


三、实现自己的定时器

|------------------------------------------------------------------------------------------------------|
| 定时器结构分析 |
| 定时器可以设定多个任务,这些任务根据时间的先后,按顺序执行。 把这些任务放在一个队列中,每次要执行的任务,肯定是离计划时间最近的那个。 因此,使用优先级队列就可以达成这一目的。 |
| 优先级队列中需要存放的元素,就是通过 schedule() 方法加入的任务。 每个元素的属性,都应该包括一份可执行的代码和一个设定的时间。 |
| 我们还需要在定时器中有一个工作线程,用于观测优先级队列的队首元素,是否达到了执行时间。 |

++代码演示实现自己的定时器:++

java 复制代码
//队列中的元素 MyTask 类;
class MyTask implements Comparable<MyTask>{
    //任务内容;
    private Runnable runnable;
    //执行时间,单位是一个毫秒级别的时间戳;
    private long time;

    public long getTime(){
        return time;
    }

    //使用任务内容和相对时间,构造MyTask;
    public MyTask(Runnable runnable,long delay){
        this.runnable = runnable;
        //系统当前时间+相对时间;
        this.time = System.currentTimeMillis()+delay;
    }

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

    //作为优先级队列的元素,需要可比较;
    @Override
    public int compareTo(MyTask o) {
        return (int) (this.time - o.time);
    }
}

//定时器类;
class MyTimer{
    //存放任务的队列;
    private PriorityQueue<MyTask> queue = new PriorityQueue<>();
    //保持监测的线程;
    private Thread t;

    //锁对象;
    private final Object locker = new Object();

    //schedule方法,向优先级队列中添加元素;
    public void schedule(Runnable runnable,long delay){
        synchronized (locker){
            MyTask task = new MyTask(runnable,delay);
            queue.offer(task);
            //入队列了,有元素了,可以唤醒线程了;
            locker.notify();
        }
    }

    //关闭定时器方法;
    public void cancel(){
        t.interrupt();
    }

    //定时器构造方法,new定时器时就把监测线程打开了;
    public MyTimer(){
        t = new Thread(()->{
            try {
                while (true){
                    //加锁,下面的判断状态和修改数据的代码需要原子;
                    synchronized (locker){
                        //队列空了,线程就等待;
                        if(queue.isEmpty()){
                            locker.wait();
                        }
                        //查看任务是否到达执行时间;
                        MyTask task = queue.peek();
                        long curTime = System.currentTimeMillis();
                        long taskTime = task.getTime();
                        if(curTime >= taskTime){
                            queue.poll();
                            task.run();
                        }else {
                            //还没到达执行时间,则计算还有多久,并根据这个时间等待;
                            locker.wait(taskTime - curTime);
                        }
                    }
                }
            }catch (InterruptedException e){
                //调用 cancel() 方法时,抛出这个异常,结束线程,并执行下述代码;
                System.out.println("定时器关闭");
            }
        });

        //线程在计时器被new出来时,就要保持运行的状态,随时监测任务队列;
        t.start();
    }
}

++代码演示执行自己实现的定时器:++

java 复制代码
    public static void main(String[] args) throws InterruptedException {
        //新建一个定时器;
        MyTimer timer = new MyTimer();
        
        //添加三个任务;
        timer.schedule(new TimerTask() {
            @Override
            public void run() {
                System.out.println("3号举手");
            }
        },3000);

        timer.schedule(new TimerTask() {
            @Override
            public void run() {
                System.out.println("2号举手");
            }
        },2000);

        timer.schedule(new TimerTask() {
            @Override
            public void run() {
                System.out.println("1号举手");
            }
        },1000);

        //等待5秒,此时上述定时器任务已经执行完毕;
        Thread.sleep(5000);
        //调用 cancel() 方法,关闭定时器。
        timer.cancel();
    }

阅读指针 -> 《经典设计模式之 -- 线程池》

<JavaEE> 经典设计模式之 -- 线程池-CSDN博客文章浏览阅读2次。简单介绍了线程池的概念,和Java标准库中的两个线程池相关类。其中,重点介绍了,ThreadPoolExecutor 类的使用和其构造方法参数的概念。另外还实现一个自己的线程池类。https://blog.csdn.net/zzy734437202/article/details/134860513

相关推荐
君鼎10 小时前
C++设计模式——单例模式
c++·单例模式·设计模式
敲代码的 蜡笔小新11 小时前
【行为型之中介者模式】游戏开发实战——Unity复杂系统协调与通信架构的核心秘诀
unity·设计模式·c#·中介者模式
令狐前生11 小时前
设计模式学习整理
学习·设计模式
敲代码的 蜡笔小新13 小时前
【行为型之解释器模式】游戏开发实战——Unity动态公式解析与脚本系统的架构奥秘
unity·设计模式·游戏引擎·解释器模式
JANYI201814 小时前
嵌入式设计模式基础--C语言的继承封装与多态
java·c语言·设计模式
敲代码的 蜡笔小新18 小时前
【行为型之观察者模式】游戏开发实战——Unity事件驱动架构的核心实现策略
观察者模式·unity·设计模式·c#
琢磨先生David21 小时前
构建优雅对象的艺术:Java 建造者模式的架构解析与工程实践
java·设计模式·建造者模式
敲代码的 蜡笔小新1 天前
【行为型之策略模式】游戏开发实战——Unity灵活算法架构的核心实现策略
unity·设计模式·c#·策略模式
_yingty_1 天前
Java设计模式-策略模式(行为型)
java·设计模式·策略模式
炎芯随笔2 天前
【C++】【设计模式】生产者-消费者模型
开发语言·c++·设计模式