mk-timer

timer是基于PriorityQueue实现的(和PriorityBlockingQueue区别, 在于没有阻塞机制, 不是线程安全的), 优先级队列是堆数据结构的典型应用
默认情况下, 按照自然顺序(其实就是默认comparator的定义), 最小的元素排在堆头
当然也可以自己重新实现comparator接口, 比如timer就用reify重新实现了comparator接口

整个过程其实比较简单, 开个timer-thread, 不断check PriorityQueue里面时间最小的timer是否已经可以触发
如果可以, 就poll出来, 调用callback, 并sleep, 都很好理解

唯一需要说的是, 这里使用Semaphore,
信号量和lock相似, 都是用于互斥
不同在于, 信号量模拟资源管理, 所以不同于lock的排他, 信号量可以接收多个aquire(取决于配置)
另外一个比较大的区别, lock是解铃还须系铃人, 谁锁谁解, 而信号量无所谓, 任何线程都可以调用release, 或acquire
这里使用信号量, 是用于在cancel-timer时, 等待timer-thread结束

(defn cancel-timer [timer]
(check-active! timer)
(locking (:lock timer)
(reset! (:active timer) false)
(.interrupt (:timer-thread timer)))
(.acquire (:cancel-notifier timer)))

因为cancel的过程就是将active置false, 然后就是调用acquire等待信号量cancel-notifier被释放

而timer-thread在线程结束前, 会release这个信号量

 

(defnk mk-timer [:kill-fn (fn [& _] )]
(let [queue (PriorityQueue. 10
(reify Comparator
(compare [this o1 o2]
(- (first o1) (first o2))
)
(equals [this obj]
true
)))
active (atom true) ;;标志位
lock (Object.) ;;创建lock对象, 由于PriorityQueue非线程安全, 所以使用locking来保证同时只有一个线程访问queue
notifier (Semaphore. 0) ;;创建信号量, 初始为0
timer-thread (Thread.
(fn []
(while @active
(try
                            ;;peek读但不从queue中取出, 先读出time看看, 符合条件再取出
(let [[time-secs _ _ :as elem] (locking lock (.peek queue))]
(if (and elem (>= (current-time-secs) time-secs))
                                ;;无法保证恰好, 只要当前时间>=time-secs, 就可以执行, 可想而知对于afn必须不能耗时, 否则会影响其他timer
;; imperative to not run the function inside the timer lock
;; otherwise, it's possible to deadlock if function deals with other locks
;; (like the submit lock)
(let [afn (locking lock (second (.poll queue)))] ;;poll从queue中取出
(afn)) ;;真正执行timer中的callback
(Time/sleep 1000)
))
(catch Throwable t
;; because the interrupted exception can be wrapped in a runtimeexception
(when-not (exception-cause? InterruptedException t)
(kill-fn t)
(reset! active false)
(throw t))
)))
(.release notifier)))]
(.setDaemon timer-thread true)
(.setPriority timer-thread Thread/MAX_PRIORITY)
(.start timer-thread)
{:timer-thread timer-thread
:queue queue
:active active
:lock lock
:cancel-notifier notifier}))

 

schedule

schedule其实就是往PriorityQueue里面插入timer

对于循环schdule, 就是在timer的callback里面, 再次schedule

(defnk schedule [timer delay-secs afn :check-active true]
(when check-active (check-active! timer))
(let [id (uuid)
^PriorityQueue queue (:queue timer)]
(locking (:lock timer)
(.add queue [(+ (current-time-secs) delay-secs) afn id])
))) (defn schedule-recurring [timer delay-secs recur-secs afn]
(schedule timer
delay-secs
(fn this []
(afn)
(schedule timer recur-secs this :check-active false)) ; this avoids a race condition with cancel-timer
))

 

使用例子

Supervisor中的使用例子, 定期的调用hb函数更新supervisor的hb

在mk-timer时, 传入的kill-fn callback, 会在timer-thread发生exception的时候被调用

:timer (mk-timer :kill-fn (fn [t]
(log-error t "Error when processing event")
(halt-process! 20 "Error when processing an event")
))
(schedule-recurring (:timer supervisor)
0
(conf SUPERVISOR-HEARTBEAT-FREQUENCY-SECS)
heartbeat-fn)

Storm-源码分析- timer (backtype.storm.timer)的更多相关文章

  1. Storm源码分析--Nimbus-data

    nimbus-datastorm-core/backtype/storm/nimbus.clj (defn nimbus-data [conf inimbus] (let [forced-schedu ...

  2. JStorm与Storm源码分析(一)--nimbus-data

    Nimbus里定义了一些共享数据结构,比如nimbus-data. nimbus-data结构里定义了很多公用的数据,请看下面代码: (defn nimbus-data [conf inimbus] ...

  3. JStorm与Storm源码分析(四)--均衡调度器,EvenScheduler

    EvenScheduler同DefaultScheduler一样,同样实现了IScheduler接口, 由下面代码可以看出: (ns backtype.storm.scheduler.EvenSche ...

  4. JStorm与Storm源码分析(三)--Scheduler,调度器

    Scheduler作为Storm的调度器,负责为Topology分配可用资源. Storm提供了IScheduler接口,用户可以通过实现该接口来自定义Scheduler. 其定义如下: public ...

  5. JStorm与Storm源码分析(二)--任务分配,assignment

    mk-assignments主要功能就是产生Executor与节点+端口的对应关系,将Executor分配到某个节点的某个端口上,以及进行相应的调度处理.代码注释如下: ;;参数nimbus为nimb ...

  6. storm源码分析之任务分配--task assignment

    在"storm源码分析之topology提交过程"一文最后,submitTopologyWithOpts函数调用了mk-assignments函数.该函数的主要功能就是进行topo ...

  7. Nimbus<三>Storm源码分析--Nimbus启动过程

    Nimbus server, 首先从启动命令开始, 同样是使用storm命令"storm nimbus”来启动看下源码, 此处和上面client不同, jvmtype="-serv ...

  8. storm源码分析之topology提交过程

    storm集群上运行的是一个个topology,一个topology是spouts和bolts组成的图.当我们开发完topology程序后将其打成jar包,然后在shell中执行storm jar x ...

  9. JStorm与Storm源码分析(五)--SpoutOutputCollector与代理模式

    本文主要是解析SpoutOutputCollector源码,顺便分析该类中所涉及的设计模式–代理模式. 首先介绍一下Spout输出收集器接口–ISpoutOutputCollector,该接口主要声明 ...

  10. Storm-源码分析- hook (backtype.storm.hooks)

    task hook 在某些task事件发生时, 如果用户希望执行一些额外的逻辑, 就需要使用hook 当前定义如下事件, emit, cleanup, spoutAck-- 用户只需要开发实现ITas ...

随机推荐

  1. 02、Quick Start for Windows phone

    在使用这个 SDK 提供的功能前,必须先添加类库的引用到你的工程里.参考: Download and add the libraries to the project. 定义你的 XAML 的 UI ...

  2. :-1: error: [debug/moc_gotocelldialog.cpp] Error 2

    环境:Qt5.3 问题描述: 我将一个已经做好可以运行的小程序拷贝了一下,放在另一个目录下打开,却无法运行,提示上面的错误,而且原程序也无法运行了.不知道为什么,还没有答案...

  3. ibatis中in语句参数传入方法

    第一种:传入参数仅有数组,iterate中不能有数组的属性名       <select id="GetEmailList_Test"  resultClass=" ...

  4. Windows 只能安装32位虚拟机问题

    查了一下相关原因,是因为cpu的虚拟化没有打开的原因 解决方法: 进去bios 里面, 进入 configuration , 将 Intel Virtual Technology 设为Enabled ...

  5. jquery设置radio选中

    <script type="text/javascript"> $(document).ready(function(){ $("input[type=rad ...

  6. 怎样实时判断socket连接状态?

    对端正常close socket,或者进程退出(正常退出或崩溃),对端系统正常关闭 这种情况下,协议栈会走正常的关闭状态转移,使用epoll的话,一般要判断如下几个情况 处理可读事件时,在循环read ...

  7. Python之美[从菜鸟到高手]--NotImplemented小析

    今天写代码时无意碰到NotImplemented,我一愣.难道是NotImplementedError的胞弟,所以略微研究了一下. NotImplemented故名思议.就是"未实现&quo ...

  8. 如何远程备份sql server数据库

      方法一(不使用SQLDMO): /// ///备份方法 /// SqlConnection conn = new SqlConnection("Server=.;Database=mas ...

  9. 谷歌字体(Google Font)初探 [翻译自Google官方文档]

    这个指南解释了如何使用Google Font的API,把网络字体添加到自己的页面上.你不需要任何的编码,你所要做的只是添加一个特定的CSS到HTML页面上,然后把字体关联到这个CSS样式. 一个快速的 ...

  10. 第二百七十四节,同源策略和跨域Ajax

    同源策略和跨域Ajax 什么是同源策略  尽管浏览器的安全措施多种多样,但是要想黑掉一个Web应用,只要在浏览器的多种安全措施中找到某种措施的一个漏洞或者绕过一种安全措施的方法即可.浏览器的各种保安措 ...