Java中分布式定时器实现和原理介绍

一、定时器:

顾名思义,定时器是定时执行的任务。定时器的应用场景很广,比方说,定时更新排行榜的用户信息、定时刷新首页列表数据到缓存等等

二、Java中实现定时任务的几种方式

1、原生态Timer,优点是方便快速,缺点是每一个任务都需要占用一个线程资源,而且任务抛异常出去后,定时任务下次就不会在执行了

2、ScheduledExecutorService,这是Java5以后提供的一个类,可以很方便的实现定时调度。

ScheduledExecutorService service = Executors.newScheduledThreadPool(5); // 创建调度服务,线程池数量为5

service .scheduleAtFixedRate(Runnable command, long initialDelay, long period, TimeUnit unit); // 开启调度,command是所要执行的任务,initialDelay是初始化延时时间,period是调度周期,unit是时间单位

3、Spring提供的定时器,例如,以下例子是每一分钟执行一次的任务

@Scheduled(cron = "0 */1 * * * ?")

public void updateXxx(){ ... }

这种方式很方便,而且也是基于线程池的方式,数量可以通过xml配置。如果项目中有很多定时任务,那么就需要相对应的调大线程池数量,不然就得排队了。

三、分布式定时器所遇到的问题

分布式定时器:简单理解就是多个定时器同时部署,定时器中的各个任务相互协作

可能遇到的问题(包括但不限于此):

1、如何保证多个定时器中同一个任务只有一个在执行

2、如何避免死锁

3、另一个诡异的问题是,明明已经加锁了,但还是被重复执行了

四、解决方案

多个定时器中的同一个任务只有一个在执行。这个时候光靠Java本身提供的锁机制是没办法实现的,需要借助第三方的力量,这里使用的是Redis,因为它高效,性能好、单节点支持qps已经超过了1万,所以性能是非常高的。其中用到的是Redis的set命令。

原型是:SET key value [EX seconds] [PX milliseconds] [NX|XX]

EX second :设置键的过期时间为 second 秒。

PX millisecond :设置键的过期时间为 millisecond 毫秒。

NX :只在键不存在时,才对键进行设置操作。

XX :只在键已经存在时,才对键进行设置操作。

例子:

set mylock 192.168.1.100 EX 5 NX

上边的例子中设置key为mylock,value为192.168.1.100,EX 5表示过期时间为5秒钟,NX表示当key不存在的时候再设置。这里为什么要把value设置为IP呢,原因是可以追踪是谁占有着这把锁。

设置成功时返回OK,失败则返回nil,利用这个特性就可以实现分布式锁了。其中设置5秒的过期时间可以避免死锁的发生

五、基于Java实现

看Git地址:https://programshare@gitlab.com/program-share/scheduler.git

六、另一个诡异的问题是,明明已经加锁了,但还是被重复执行了

这个原因是由于,你部署的两台机器中可能存在时间差。比方说,同一个时刻A机器的当前时间为:2017-03-17 16:39:58,B机器的当前时间为:2017-03-17 16:40:00,其中相差两秒中。此时B机器刚好00秒开始执行,但是呢,你的定时任务不到2秒就执行完了,锁也正常的释放了。所以A机器到了00秒之后也开始执行.....因此问题产生了。解决方案有很多种,简单的方式就是用时间间隔隔开。

  • 0
    点赞
  • 4
    收藏
    觉得还不错? 一键收藏
  • 3
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论 3
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值