【JavaEE初阶】定时器

📕 引言

定时器是什么?

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

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

🌳 Java标准库中的定时器

  • 标准库中提供了一个 Timer 类. Timer 类的核心方法为 schedule .

  • schedule 包含两个参数.

  • 第一个参数指定即将要执行的任务代码,不是Runnable,而是Timer Task(其实也是实现了Runnable)

  • 第二个参数指定多长时间之后执行 (单位为毫秒),以当前执行 schedule 的时刻为基准,继续等 delay 时间之后再去进一步执行

代码:

🎄 模拟实现定时器

🚩 定时器的构成

1,一个带优先级的阻塞队列

  • 为啥要带优先级呢?
  • 因为阻塞队列中的任务都有各自的执行时刻 (delay). 最先执行的任务一定是 delay 最小的. 使用带优先级的队列就可以高效的把这个 delay 最小的任务找出来.
  • 队列中的每个元素是一个 MyTask 对象.

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

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

📌 实现MyTimerTask类

定义一个类表示一个任务(基于Runnable)

📌 实现MyTimer类

通过一定的数据结构,保存多个任务

直观的做法使用List:如果这里的元素很多,后序用来执行任务的线程,就需要不停的循环扫描这里的任务,分别判定是否要执行,循环扫描的开销就很大

使用优先级队列:可以把这些任务通过优先级队列保存起来,按照时间作为优先级的先后标准,就可以做到队首元素就是时间最靠前的任务,扫描线程只需要关注队首元素即可(时间最靠前的任务都没到点,剩下的任务就更不会到点了)。

需要一个线程来负责执行这里的任务(在指定时间去执行)

由于优先级队列本身就不是线程安全的,在MyTimer类中,调用 schedule 是一个线程,入队列操作。红色方框中的扫描线程是另一个线程,出队列操作。这时候很明显就是两个线程来针对同一个队列进行操作,此时就需要进行加锁。

注意:直接使用阻塞队列是否就线程安全了?下面讲到

加锁:

在入队列的时候先加锁,再去入队列。针对while循环也进行加锁。

📌 解决上述存在的问题

上述代码到这里呢,还存在三个比较核心的问题:

1,try-catch

当前代码中并没有阻塞等待,加了这个也没有用,反而报错了!那么上述扫描线程的代码是否要有阻塞等待??

所以这里的else就不适合写continue,使用wait来进行控制,但是不能死等,等待时间为任务时间减去当前时间即可。

那么对于判定队列是否为空,也可进行wait 

2,使用阻塞队列问题:

3,我们要把任务对象,通过优先级队列管理起来,那么啥样的对象能放进优先级队列,是随便写个对象吗?

对于优先级队列,我们讲过,元素之间要根据什么进行比较,所以对于自己实现的类要实现比较器,手动的去规定比较规则。

完整代码:

测试:

  • 11
    点赞
  • 3
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值