当前位置: 首页 > wzjs >正文

广东省建设工程网站网站建设公司新报价

广东省建设工程网站,网站建设公司新报价,台州哪里做网站,拜年小程序制作接上文: Redisson的RDelayedQueue Redisson他是Redis的儿子(Redis son),基于Redis实现了非常多的功能,其中最常使用的就是Redis分布式锁的实现,但是除了实现Redis分布式锁之外,它还实现了延迟…

接上文:

Redisson的RDelayedQueue

Redisson他是Redis的儿子(Redis son),基于Redis实现了非常多的功能,其中最常使用的就是Redis分布式锁的实现,但是除了实现Redis分布式锁之外,它还实现了延迟队列的功能。

先来个demo

引入pom

<dependency><groupId>org.redisson</groupId><artifactId>redisson</artifactId><version>3.13.1</version>
</dependency>

封装了一个RedissonDelayQueue类

@Component
@Slf4j
public class RedissonDelayQueue {private RedissonClient redissonClient;private RDelayedQueue<String> delayQueue;private RBlockingQueue<String> blockingQueue;@PostConstructpublic void init() {initDelayQueue();startDelayQueueConsumer();}private void initDelayQueue() {Config config = new Config();SingleServerConfig serverConfig = config.useSingleServer();serverConfig.setAddress("redis://localhost:6379");redissonClient = Redisson.create(config);blockingQueue = redissonClient.getBlockingQueue("SANYOU");delayQueue = redissonClient.getDelayedQueue(blockingQueue);}private void startDelayQueueConsumer() {new Thread(() -> {while (true) {try {String task = blockingQueue.take();log.info("接收到延迟任务:{}", task);} catch (Exception e) {e.printStackTrace();}}}, "SANYOU-Consumer").start();}public void offerTask(String task, long seconds) {log.info("添加延迟任务:{} 延迟时间:{}s", task, seconds);delayQueue.offer(task, seconds, TimeUnit.SECONDS);}}

这个类在创建的时候会去初始化延迟队列,创建一个RedissonClient对象,之后通过RedissonClient对象获取到RDelayedQueue和RBlockingQueue对象,传入的队列名字叫SANYOU,这个名字无所谓。

当延迟队列创建之后,会开启一个延迟任务的消费线程,这个线程会一直从RBlockingQueue中通过take方法阻塞获取延迟任务。

添加任务的时候是通过RDelayedQueue的offer方法添加的。

controller类,通过接口添加任务,延迟时间为5s

@RestController
public class RedissonDelayQueueController {@Resourceprivate RedissonDelayQueue redissonDelayQueue;@GetMapping("/add")public void addTask(@RequestParam("task") String task) {redissonDelayQueue.offerTask(task, 5);}}

启动项目,在浏览器输入如下连接,添加任务

http://localhost:8080/add?task=sanyou

静静等待5s,成功获取到任务。

图片

实现原理

如下是Redisson延迟队列的实现原理

图片

SANYOU前面的前缀都是固定的,Redisson创建的时候会拼上前缀。

  • redisson_delay_queue_timeout:SANYOU,sorted set数据类型,存放所有延迟任务,按照延迟任务的到期时间戳(提交任务时的时间戳 + 延迟时间)来排序的,所以列表的最前面的第一个元素就是整个延迟队列中最早要被执行的任务,这个概念很重要

  • redisson_delay_queue:SANYOU,list数据类型,也是存放所有的任务,但是研究下来发现好像没什么用。。

  • SANYOU,list数据类型,被称为目标队列,这个里面存放的任务都是已经到了延迟时间的,可以被消费者获取的任务,所以上面demo中的RBlockingQueue的take方法是从这个目标队列中获取到任务的

  • redisson_delay_queue_channel:SANYOU,是一个channel,用来通知客户端开启一个延迟任务

任务提交的时候,Redisson会将任务放到redisson_delay_queue_timeout:SANYOU中,分数就是提交任务的时间戳+延迟时间,就是延迟任务的到期时间戳

Redisson客户端内部通过监听redisson_delay_queue_channel:SANYOU这个channel来提交一个延迟任务,这个延迟任务能够保证将redisson_delay_queue_timeout:SANYOU中到了延迟时间的任务从redisson_delay_queue_timeout:SANYOU中移除,存到SANYOU这个目标队列中。

于是消费者就可以从SANYOU这个目标队列获取到延迟任务了。

所以从这可以看出,Redisson的延迟任务的实现跟前面说的MQ的实现都是殊途同归,最开始任务放到中间的一个地方,叫做redisson_delay_queue_timeout:SANYOU,然后会开启一个类似于定时任务的一个东西,去判断这个中间地方的消息是否到了延迟时间,到了再放到最终的目标的队列供消费者消费。

Redisson的这种实现方式比监听Redis过期key的实现方式更加可靠,因为消息都存在list和sorted set数据类型中,所以消息很少丢。

上述说的两种Redis的方案更详细的介绍,可以查看我之前写的用Redis实现延迟队列,我研究了两种方案,发现并不简单这篇文章。

Netty的HashedWheelTimer

先来个demo
@Slf4j
public class NettyHashedWheelTimerDemo {public static void main(String[] args) {HashedWheelTimer timer = new HashedWheelTimer(100, TimeUnit.MILLISECONDS, 8);timer.start();log.info("提交延迟任务");timer.newTimeout(timeout -> log.info("执行延迟任务"), 5, TimeUnit.SECONDS);}}

测试结果

图片

实现原理

图片

如图,时间轮会被分成很多格子(上述demo中的8就代表了8个格子),一个格子代表一段时间(上述demo中的100就代表一个格子是100ms),所以上述demo中,每800ms会走一圈。

当任务提交的之后,会根据任务的到期时间进行hash取模,计算出这个任务的执行时间所在具体的格子,然后添加到这个格子中,通过如果这个格子有多个任务,会用链表来保存。所以这个任务的添加有点像HashMap储存元素的原理。

HashedWheelTimer内部会开启一个线程,轮询每个格子,找到到了延迟时间的任务,然后执行。

由于HashedWheelTimer也是单线程来处理任务,所以跟Timer一样,长时间运行的任务会导致其他任务的延时处理。

前面Redisson中提到的客户端延迟任务就是基于Netty的HashedWheelTimer实现的。

Hutool的SystemTimer

Hutool工具类也提供了延迟任务的实现SystemTimer

demo
@Slf4j
public class SystemTimerDemo {public static void main(String[] args) {SystemTimer systemTimer = new SystemTimer();systemTimer.start();log.info("提交延迟任务");systemTimer.addTask(new TimerTask(() -> log.info("执行延迟任务"), 5000));}}

执行结果

图片

Hutool底层其实也用到了时间轮。

Qurtaz

Qurtaz是一款开源作业调度框架,基于Qurtaz提供的api也可以实现延迟任务的功能。

demo

依赖

<dependency><groupId>org.quartz-scheduler</groupId><artifactId>quartz</artifactId><version>2.3.2</version>
</dependency>

SanYouJob实现Job接口,当任务到达执行时间的时候会调用execute的实现,从context可以获取到任务的内容

@Slf4j
public class SanYouJob implements Job {@Overridepublic void execute(JobExecutionContext context) throws JobExecutionException {JobDetail jobDetail = context.getJobDetail();JobDataMap jobDataMap = jobDetail.getJobDataMap();log.info("获取到延迟任务:{}", jobDataMap.get("delayTask"));}
}

测试类

public class QuartzDemo {public static void main(String[] args) throws SchedulerException, InterruptedException {// 1.创建Scheduler的工厂SchedulerFactory sf = new StdSchedulerFactory();// 2.从工厂中获取调度器实例Scheduler scheduler = sf.getScheduler();// 6.启动 调度器scheduler.start();// 3.创建JobDetail,Job类型就是上面说的SanYouJobJobDetail jb = JobBuilder.newJob(SanYouJob.class).usingJobData("delayTask", "这是一个延迟任务").build();// 4.创建TriggerTrigger t = TriggerBuilder.newTrigger()//任务的触发时间就是延迟任务到的延迟时间.startAt(DateUtil.offsetSecond(new Date(), 5)).build();// 5.注册任务和定时器log.info("提交延迟任务");scheduler.scheduleJob(jb, t);}
}

执行结果:

图片

实现原理

核心组件

  • Job:表示一个任务,execute方法的实现是对任务的执行逻辑

  • JobDetail:任务的详情,可以设置任务需要的参数等信息

  • Trigger:触发器,是用来触发业务的执行,比如说指定5s后触发任务,那么任务就会在5s后触发

  • Scheduler:调度器,内部可以注册多个任务和对应任务的触发器,之后会调度任务的执行

图片

启动的时候会开启一个QuartzSchedulerThread调度线程,这个线程会去判断任务是否到了执行时间,到的话就将任务交给任务线程池去执行。

无限轮询延迟任务

无限轮询的意思就是开启一个线程不停的去轮询任务,当这些任务到达了延迟时间,那么就执行任务。

demo
@Slf4j
public class PollingTaskDemo {private static final List<DelayTask> DELAY_TASK_LIST = new CopyOnWriteArrayList<>();public static void main(String[] args) {new Thread(() -> {while (true) {try {for (DelayTask delayTask : DELAY_TASK_LIST) {if (delayTask.triggerTime <= System.currentTimeMillis()) {log.info("处理延迟任务:{}", delayTask.taskContent);DELAY_TASK_LIST.remove(delayTask);}}TimeUnit.MILLISECONDS.sleep(100);} catch (Exception e) {}}}).start();log.info("提交延迟任务");DELAY_TASK_LIST.add(new DelayTask("三友的java日记", 5L));}@Getter@Setterpublic static class DelayTask {private final String taskContent;private final Long triggerTime;public DelayTask(String taskContent, Long delayTime) {this.taskContent = taskContent;this.triggerTime = System.currentTimeMillis() + delayTime * 1000;}}}

任务可以存在数据库又或者是内存,看具体的需求,这里我为了简单就放在内存里了。

执行结果:

图片

这种操作简单,但是就是效率低下,每次都得遍历所有的任务。


文章转载自:

http://WSDZAgxN.hxLch.cn
http://CZOiYy1v.hxLch.cn
http://tx6XpWfl.hxLch.cn
http://twjhDe2i.hxLch.cn
http://0vQ4XxCq.hxLch.cn
http://vOR9ENzP.hxLch.cn
http://9zYlO1T5.hxLch.cn
http://3XtWebXm.hxLch.cn
http://n98rOxB3.hxLch.cn
http://XHdTRmYi.hxLch.cn
http://3twm6TkG.hxLch.cn
http://XAmuLolA.hxLch.cn
http://TLS1mBCE.hxLch.cn
http://tH00rS3P.hxLch.cn
http://x0yA3K4V.hxLch.cn
http://C9uA7L3B.hxLch.cn
http://YaoTbXXi.hxLch.cn
http://5peDX7jl.hxLch.cn
http://hyaQdf3p.hxLch.cn
http://et5WA7Ca.hxLch.cn
http://LYmPoSfZ.hxLch.cn
http://0eVrH7cj.hxLch.cn
http://DnQ5HrjM.hxLch.cn
http://wIxJLaCO.hxLch.cn
http://zVIg0WGI.hxLch.cn
http://tpoBc04n.hxLch.cn
http://PFWKrt3Z.hxLch.cn
http://8g4MaPD8.hxLch.cn
http://zTWR53OA.hxLch.cn
http://KTFtAGtA.hxLch.cn
http://www.dtcms.com/wzjs/708115.html

相关文章:

  • 网站客户体验如何设计网站风格
  • 网站建设设计合同书做公司网站需要什么手续
  • 怎样用自己的服务器做网站淘宝购物平台
  • 北京西站停车场收费标准爱妮微如何做网站链接的网址
  • 石家庄新钥匙网站erp实施顾问
  • 哔哩哔哩高能建站做彩票网站网址
  • 免费网站建设 免备案网站服务器错误怎么办
  • 电商食品网站建设医疗网站设计风格
  • 专门做护理PDCA的网站visual c 网站开发
  • 全国建设项目竣工验收公示网站怎样实现wordpress订单提醒功能
  • 公益网站设计做机械的老板都看什么网站
  • 攀枝花网站建设wordpress公司官网主题
  • 商洛网站设计网站做动态还是静态
  • 图片做网站连接站长工具源码
  • 莱州教研室网站网站空间密码
  • 织梦cms建站泉州网上房地产
  • 北京seo顾问石家庄seo外包的公司
  • 成武网站建设王烨老师
  • 广东手机网站建设报价表iis能搭WordPress
  • 专业做网站套餐网站建设设计外包公司
  • 电话卡代理平台营销网站的专业性诊断评价和优化
  • 智能网站开发工具西地那非是什么药
  • 网站怎样做的有吸引力建网站的软件
  • 网站建设初学者必学辽宁省住建厅建设网站
  • 珠海仿站定制模板建站用哪个平台做网站好
  • 百度站长验证网站失败注册安全工程师建设工程网站
  • 论述网站建设及运营流程重庆企业网站制作
  • 公司企业网站建设网络销售推广平台
  • 苏州网站建设渠道南县网站建设推荐
  • 国土资源局加强网站建设上海市企业服务云官网