<多线程章节十> 定时器的使用方法以及定时器的模拟实现

文章目录

  • 专栏导读
  • Java标准库中的定时器类
  • 模拟实现定时器

专栏导读

本篇文章收录于多线程,也欢迎翻阅博主的其他文章,可能也会让你有不一样的收获
JavaSE多线程数据结构

闹钟大家一定都使用过,当闹钟响的时候,就表示我们该起床了,或者是手机上的定时发短信,等到时间达到时,就会按照我们的要去发送短信等;定时器也就是这样一种工作组件,约定一个时间,当时间达到时,就会执行代码

定时器经常用于网络通信中,例如,当客户端向服务器发出一个请求后,就要等待服务器进行响应,但是,如果服务器一直没响应怎么办,是因为请求没发过去?响应没传过来?服务器出问题了等等,这中间你也不知道发生了什么,这时候,客户端难道就一直等着,等到天荒地老?所以,对于客户端而言,就需要一个等待时间,如果等待时间到了,是重新再发送一遍,还是放弃发送,还是其他的操作等等………

Java标准库中的定时器类

在Java的util包中,提供了一个Timer类,这个类就是一个定时器,下面通过代码演示:

public class MyTimer {
    public static void main(String[] args) {
        Timer timer = new Timer();
        timer.schedule(new TimerTask() {
            //给定时器安排一个任务,约定在xxx时间后开始执行
            @Override
            public void run() {
                System.out.println("定时器中任务开始执行");
            }
        }, 3000);//指定定时时间,约定在三秒之后开始执行
        System.out.println("程序执行");
    }
}

<多线程章节十> 定时器的使用方法以及定时器的模拟实现_第1张图片

在执行schedule方法的时候,就是把这个任务放到了timer对象中,而且,在timer对象中,也包含了一个线程,这个线程叫作”扫描线程“,等约定时间到了以后,扫描线程就开始执行这个任务;然后通过执行结果也可以看到,定时器中的任务执行完之后,进程并没有结束,而是处于等待其他任务安排进来,所以由此得出,Timer中的线程会阻止进程结束,在Timer中同样也可以安排多个任务

<多线程章节十> 定时器的使用方法以及定时器的模拟实现_第2张图片

在学习完如何使用一个定时器后,我们应该还知道如何实现一个简单的定时器

模拟实现定时器

实现一个定时器主要考虑一下几个步骤:

 class MyTimerTask {
        //顶一个一个任务
    private Runnable runnable;
    //定义一个定时时间
    public long time;
    public MyTimerTask(Runnable runnable, long delay) {
        this.runnable = runnable;
        this.time = System.currentTimeMillis()+delay;
    }
    public Runnable get_runnable() {
        return runnable;
    }
}
public class MyTimer {
   //定义一个队列用于组织任务
    private PriorityQueue<MyTimerTask> priorityQueue = new PriorityQueue<>(new Comparator<MyTimerTask>() {
        //自定义比较方法
       @Override
       public int compare(MyTimerTask o1, MyTimerTask o2) {
           return (int)(o1.time - o2.time);
       }
   });

    //定义一个锁对象
    Object locker = new Object();

    //定义一个schedule方法
    public void schedule(Runnable runnable, long time) {

        /*
        因为是其他的线程调用schedule,然后对队列进行操作,而扫扫描线程也是对队列进行操作,
        这也就构成了两个线程对同一个数据进行操作,就可能会出现线程安全问题,因此要进行加锁
         */
        synchronized (locker) {
            priorityQueue.offer(new MyTimerTask(runnable, time));
            locker.notify();
        }
    }

    //在构造方法中定义一个扫描线程
    public MyTimer() {
        Thread thread = new Thread(() -> {
            while(true) {
                //检查队列中的任务
                check_task();
            }
        });
        thread.start();
    }
    private void check_task() {
        try {
            synchronized (locker) {
                //当队列为空时,阻塞等待
                //使用while进行判断,防止唤醒wait时,队列仍然为空
                while (priorityQueue.isEmpty()) {
                    locker.wait();
                }
                MyTimerTask myTimerTask = priorityQueue.peek();
                //判断当前时间与定时时间
                long curTime = System.currentTimeMillis();
                if(curTime >= myTimerTask.time) {
                    //当前时间大于定时时间,开始执行任务
                    myTimerTask.get_runnable().run();
                    //任务执行完后删除
                    priorityQueue.poll();
                }else {
                    //为了防止忙等,在这里进行带有时间的wait等待
                    //当时间到了以后,再进行循环,开始执行任务
                    locker.wait(curTime - myTimerTask.time);
                }
            }
        }catch (InterruptedException e) {
            e.printStackTrace();
        }
    }
}

<多线程章节十> 定时器的使用方法以及定时器的模拟实现_第3张图片

你可能感兴趣的:(多线程,开发语言,java,java-ee)