多线程 如何自己实现定时器

Posted Perceus

tags:

篇首语:本文由小常识网(cha138.com)小编为大家整理,主要介绍了多线程 如何自己实现定时器相关的知识,希望对你有一定的参考价值。

@TOC


什么是定时器

  • 定时器是多线程编程中的一个重要的组件
  • 好比一个闹钟 定好一个时间让一个线程去执行
  • 定时器在网络编程中特别常见

比如:

那么,我们就可以使用 代码中的定时器,来实现类似的功能。

先介绍标准库的定时器用法,然后再看看如何自己实现一个定时器


标准库的定时器用法

schedule方法,有两个参数

  1. 任务
  2. 多长时间之后执行


如何自己实现一个定时器

一个问题:Timer 类 的内部需要什么东西?

Timer 的 工作内容入手

  1. 管理很多的任务
  2. 执行时间到了的任务

1. 描述任务

// 创建一个类,来描述一个具体的任务
class MyTask
    // 任务具体要做什么
    private Runnable runnable;
    // 任务具体的执行时间:保存任务要执行的毫秒级时间戳
    private long time;
    // after 是一个时间间隙,不是绝对的时间戳的值
    public MyTask(Runnable runnable,long after)
        this.runnable = runnable;
        // 很简单,意思就是从当前时间开始, after 秒之后,这个任务被执行。
        this.time = System.currentTimeMillis()+after;
    
    // 通过调用这里 run方法,来执行我们任务具体要做什么
    public void run()
        runnable.run();
    

2. 组织任务


3. 执行时间到了的任务


上述代码中存在两个非常严重的问题!!!


代码

import java.util.concurrent.PriorityBlockingQueue;

// 创建一个类,来描述一个具体的任务
class MyTask implements Comparable<MyTask>
    // 任务具体要做什么
    private Runnable runnable;
    // 任务具体的执行时间:保存任务要执行的毫秒级时间戳
    private long time;
    // after 是一个时间间隙,不是绝对的时间戳的值
    public MyTask(Runnable runnable,long after)
        this.runnable = runnable;
        // 很简单,意思就是从当前时间开始, after 秒之后,这个任务被执行。
        this.time = System.currentTimeMillis()+after;
    
    // 通过调用这里 run方法,来执行我们任务具体要做什么
    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 PriorityBlockingQueue<MyTask> queue = new PriorityBlockingQueue<>();
    public void schedule(Runnable runnable,long after)
        MyTask task = new MyTask(runnable,after);
        queue.put(task);
        synchronized(locker)
            locker.notify();
        
    
    private Object locker = new Object();

    public MyTimer()
        Thread t = new Thread(()->
           while(true)
               try 
                   // 取出队首元素
                   MyTask task =queue.take();
                   //再比较一下看看当前这个任务时间到了没
                   long curTime = System.currentTimeMillis();
                   // 拿当前时间 和 任务执行时间进行比较
                   if(curTime < task.getTime())
                       //时间还没到,把任务再塞回到队列中
                       queue.put(task);
                       // 指定一个等待时间
                       synchronized(locker)
                          locker.wait(task.getTime() - curTime);
                       
                   else
                       // 时间到了,执行这个任务
                       task.run();
                   
                catch (InterruptedException e) 
                   e.printStackTrace();
               
           
        );
        t.start();
    


public class Test25 
    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");
    


以上是关于多线程 如何自己实现定时器的主要内容,如果未能解决你的问题,请参考以下文章

C语言 用定时器 模拟多线程

计时器与多线程(无聊应试向)

29多线程(线程池定时器)将一个文件复制多次拆分文件并合并多线程复制文件

29多线程(线程池定时器)将一个文件复制多次拆分文件并合并多线程复制文件

多线程程序的 C++ 定时器中断

定时任务多线程的实现