0
点赞
收藏
分享

微信扫一扫

JavaEE之线程(9) _定时器的实现代码

豆丁趣 2024-05-28 阅读 28

前言

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

在这里插入图片描述

 在受上述场景中,当客户端发出去请求之后, 就要等待响应,如果服务器迟迟没有响应,也不清楚,这个请求就没发过去? 响应丢了?服务器出问题了?
 对于客户端来说,不能无限的等,需要有一个最大的期限,到达这个最大的期限之后,是重新再发一遍,还是彻底放弃,还是什么其他的方式。
类似于以上场景就需要用到定时器。


一、标准库中的定时器

 在标准库中提供了一个 Timer 类,它的核心方法为 schedule 。

参考代码如下:

Timer timer = new Timer();
timer.schedule(new TimerTask() {
	@Override
	public void run() {
		System.out.println("hello");
	}
}, 3000);

二、实现一个定时器

在实现一个定时器(Timer)前,我们需要考虑三个问题

2.1 定时器的构成

1. 一个带优先级的阻塞队列;
2. 队列中的每个元素是一个 Task 对象;
3.Task 中带有一个时间属性, 队首元素就是即将要执行的对象;
4. 同时有一个 worker 线程一直扫描队首元素, 看队首元素是否需要执行。

2.2实现过程

定时器的完整实现代码:

package Timer9;

import java.util.PriorityQueue;

/**
 * @author Zhang
 * @date 2024/5/1016:43
 * @Description:
 */
//通过这个类,描述了一个任务
class MyTimerTak implements Comparable<MyTimerTak>{
    //要有一个要执行的任务
    private Runnable runnable;
    //执行任务的时间
    private  long time;
    // 此处的delay,就是schedule方法传入的相对时间
    public MyTimerTak(Runnable runnable, long delay ) {
        this.runnable = runnable;
        this.time = System.currentTimeMillis()+delay;
    }

    @Override
    public int compareTo(MyTimerTak o) {
        //这样写,就是让队首元素是最小时间的值
        return (int)(this.time - o.time);
    }

    public long getTime(){
        return  time;
    }

    public  Runnable getRunnable(){
        return  runnable;
    }
}

//自己的定时器
class  MyTimer{
    //使用一个数据结构,保存所有要安排的任务
    PriorityQueue<MyTimerTak> queue = new PriorityQueue<>();

    //使用这个ui想作为锁对象
    private Object locker = new Object();
    public void schedule(Runnable runnable,long delay){
        synchronized (locker){
            queue.offer(new MyTimerTak(runnable, delay));
        }

    }

    //扫描线程
    public MyTimer(){
        //创建一个线程
        Thread t = new Thread(()->{
            while (true){
                try{
                    synchronized (locker){
                        //不要使用if 作为wait的判定条件,应该使用while
                        //使用 while 的目的是为了在 wait被唤醒的时候,再次确认一下条件
                        while(queue.isEmpty()){
                            //使用wait等待
                             //这里的wait,需要另外的线程唤醒
                            //添加了新任务,就会被唤醒
                            locker.wait();
                        }
                        MyTimerTak tak = queue.peek();
                        //比较当前的队首是否可以执行元素
                        long curTime = System.currentTimeMillis();
                        if (curTime >= tak.getTime()){
                            //当前时间已经达到了人物事件,就可以执行任务了
                            tak.getRunnable().run();
                            //任务执行结束,就可以从队列中删除了
                            queue.poll();
                        }else {
                            //当前时间还没达到任务时间,暂时不执行任务
                            locker.wait(tak.getTime() - curTime);

                        }
                    }

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


}

定时器的调用和演示:

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

        timer.schedule(new Runnable() {
            @Override
            public void run() {
                System.out.println("1000");
            }
        },1000);

    }
}

总结

 以上就是今天要讲的内容,本文仅仅简单介绍定时器的使用场景,标准库中的定时器,定时器的实现代码。

举报

相关推荐

0 条评论