storm定时器与java.util.Timer定时器比较相似。java.util.Timer定时器实际上是个线程,定时调度所拥有的TimerTasks;storm定时器也有一个线程负责调度所拥有的"定时任务"。storm定时器的"定时任务"是一个vector类型的数据[time, callback, uuid],内有会有三个值,分别是时间、函数、和uuid,很好理解,时间表示该定时任务什么时候执行,函数表示要执行的函数,uuid用于标识该"定时任务"。"定时任务"被存放到定时器的PriorityQueue队列中(和PriorityBlockingQueue区别,在于没有阻塞机制,不是线程安全的)。优先级队列是堆数据结构的典型应用,如果不提供Comparator的话,优先队列中元素默认按自然顺序排列,也就是数字默认是小的在队列头,字符串则按字典序排列(参阅 Comparable),也可以根据 Comparator 来指定,这取决于使用哪种构造方法。优先级队列不允许null元素。依靠自然排序的优先级队列还不允许插入不可比较的对象(这样做可能导致 ClassCastException)。当然也可以自己重新实现Comparator接口, 比如storm定时器就用reify重新实现了Comparator接口。storm定时器的执行过程比较简单,通过timer-thread,不断检查PriorityQueue里面时间最小的"定时任务"是否已经可以触发了, 如果可以(当前时间>=执行时间),就poll出来,调用callback,并sleep。storm定时器相关的函数均定义在timer.clj文件中,storm定时器是由mk-timer函数创建的,mk-timer函数定义如下:

mk-timer函数
()
       ))))
                            (catch Throwable t
                              ;; Because the interrupted exception can be
                              ;; wrapped in a RuntimeException.
                              ;; 检查是否是InterruptedException,如果是InterruptedException,说明线程是由于接收interrupt信号而中断的,不做异常处理,否则调用kill-fn函数、修改线程状                               ;; 态并抛出该异常
                              (when-not (exception-cause? InterruptedException t)
                                (kill-fn t)
                                (reset! active false)
                                (throw t)))))
                        ;; release notifier信号量,标识timer—thread运行结束
                        (.release notifier)) thread-name)]
   ;; 设置timer-thread为守护线程
   (.setDaemon timer-thread true)
   ;; 设置timer-thread为最高优先级
   (.setPriority timer-thread Thread/MAX_PRIORITY)
   ;; 启动timer-thread线程
   (.start timer-thread)
   ;; 返回该定时器的"属性"
   {:timer-thread timer-thread
    :queue queue
    :active active
    :lock lock
    :cancel-notifier notifier}))

我们可以通过调用cancel-timer函数中断一个timer-thread线程,cancel-timer函数定义如下:

cancel-timer函数
(defn cancel-timer
 [timer]
 ;; 检查timer状态是否是"active",如果不是则抛出异常
 (check-active! timer)
 ;; 加锁
 (locking (:lock timer)
   ;; 将timer的状态active设置成false,即"dead"
   (reset! (:active timer) false)
   ;; 调用interrupt方法,中断线程,通过mk-timer函数我们可以知道在线程的run方法内调用了sleep方法,当接收到中断新号后会抛出InterruptedException异常使线程退出
   (.interrupt (:timer-thread timer)))
 ;; acquire timer中的notifier信号量,因为只有当线程结束前才会release notifier信号量,所以此处是等待线程结束
 (.acquire (:cancel-notifier timer)))

check-active!函数定义如下:

check-active!函数
(defn- check-active!
 [timer]
 (when-not @(:active timer)
   (throw (IllegalStateException. "Timer is not active"))))

通过调用schedule函数和schedule-recurring函数我们可以向storm定时器中添加"定时任务"。schedule函数定义如下:

schedule函数
(defnk schedule
 ;; timer绑定定时器,delay-secs绑定"定时任务"相对当前时间的延迟时间,afn绑定callback函数,check-active是否需要检查定时器
 [timer delay-secs afn :check-active true]
 ;; 检查定时器状态
 (when check-active (check-active! timer))
 (let [id (uuid)
       ^PriorityQueue queue (:queue timer)]
   ;; 加锁,执行时间=当前时间+延迟时间,将"定时任务"的vector类型数据添加到PriorityQueue队列中
   (locking (:lock timer)
     (.add queue [(+ (current-time-millis) (secs-to-millis-long delay-secs)) afn id]))))

schedule-recurring函数定义如下:schedule-recurring函数也很简单,与schedule函数的区别就是在"定时任务"的callback函数中又添加了一个相同的"定时任务"。schedule函数的语义可以理解成向定时器添加

一个"一次性任务",schedule-recurring函数的语义可以理解成向定时器添加"一个周期执行的定时任务"(开始执行时间=当前时间+延迟时间,然后每隔recur-secs执行一次),

schedule-recurring函数
(defn schedule-recurring
 [timer delay-secs recur-secs afn]
 (schedule timer
           delay-secs
           (fn this []
             (afn)
             ; This avoids a race condition with cancel-timer.
             (schedule timer recur-secs this :check-active false))))

nimbus检查心跳和重分配任务的实现就是通过schedule-recurring函数向storm定时器添加了一个"周期任务"实现的。

(
       (conf NIMBUS-MONITOR-FREQ-SECS)
       (fn []
         (when (conf NIMBUS-REASSIGN)
           (locking (:submit-lock nimbus)
             (mk-assignments nimbus)))
         (do-cleanup nimbus)
         ))

storm定时器timer源码分析-timer.clj的更多相关文章

  1. Nimbus<二>storm启动nimbus源码分析-nimbus.clj

    nimbus是storm集群的"控制器",是storm集群的重要组成部分.我们可以通用执行bin/storm nimbus >/dev/null 2>&1 &a ...

  2. storm启动nimbus源码分析-nimbus.clj

    nimbus是storm集群的"控制器",是storm集群的重要组成部分.我们可以通用执行bin/storm nimbus >/dev/null 2>&1 &a ...

  3. storm操作zookeeper源码分析-cluster.clj

    storm操作zookeeper的主要函数都定义在命名空间backtype.storm.cluster中(即cluster.clj文件中).backtype.storm.cluster定义了两个重要p ...

  4. storm启动supervisor源码分析-supervisor.clj

    supervisor是storm集群重要组成部分,supervisor主要负责管理各个"工作节点".supervisor与zookeeper进行通信,通过zookeeper的&qu ...

  5. storm shell命令源码分析-shell_submission.clj

    当我们在shell里执行storm shell命令时会调用shell_submission.clj里的main函数.shell_submission.clj如下: shell_submission.c ...

  6. supervisor启动worker源码分析-worker.clj

    supervisor通过调用sync-processes函数来启动worker,关于sync-processes函数的详细分析请参见"storm启动supervisor源码分析-superv ...

  7. Unity时钟定时器插件——Vision Timer源码分析之二

      Unity时钟定时器插件——Vision Timer源码分析之二 By D.S.Qiu 尊重他人的劳动,支持原创,转载请注明出处:http.dsqiu.iteye.com 前面的已经介绍了vp_T ...

  8. worker启动executor源码分析-executor.clj

    在"supervisor启动worker源码分析-worker.clj"一文中,我们详细讲解了worker是如何初始化的.主要通过调用mk-worker函数实现的.在启动worke ...

  9. Java并发编程笔记之Timer源码分析

    timer在JDK里面,是很早的一个API了.具有延时的,并具有周期性的任务,在newScheduledThreadPool出来之前我们一般会用Timer和TimerTask来做,但是Timer存在一 ...

随机推荐

  1. 第十二、模块二、调用中国天气网和qqOnline及TrainTimeWebService接口来突出Json方法

    一. 浏览网页的时候,发送的请求.服务器反回来的永远是字符串,由于服务器后台使用的语言不通,所以就需要用工具反解,这里用到了json json方法一 json.loads()将字符串转化为python ...

  2. [IDE]Intellij Idea学习整理

    一.优化 1.在IDEA的安装目录的bin目录下,找到如图所示的两个文件,根据所在系统是32位还是64位打开相应的文件. 2.以64位为例,打开idea64.exe.vmoptions. 如图修改参数 ...

  3. bagging与boosting集成学习、随机森林

    主要内容: 一.bagging.boosting集成学习 二.随机森林 一.bagging.boosting集成学习 1.bagging: 从原始样本集中独立地进行k轮抽取,生成训练集.每轮从原始样本 ...

  4. RabbitMQ事务确认机制(生产者)

    消息确认机制 生产者 消费者 消费者如何确保消息一定消费成功 队列和消费者建立长连接,推送或者拉取形式. 消费者通过自动应答或者手动应答,队列服务器等待应答结果,如果没有应答结果那么保留给下一个消费者 ...

  5. python第四篇:linux命令行总结 + 自动备份Python程序

    由于最近需要学习Python爬虫相关的知识,所以就先从Python基础.Linux基础开始进行了学习,下面主要是总结了常见的Linux的命令行.最后为了巩固学到的东西,尝试写了个自动备份的Python ...

  6. cocos2dx 中 string 转json

    string jsonData = warriors.toStyledString().c_str(); Json::Value parseData; Json::Reader reader; rea ...

  7. 在windows下进行linux开发:利用Vagrant+virtualbox

    1,介绍Vagrant 我们做web开发的时候经常要安装各种本地测试环境,比如apache,php,mysql,redis等等.出于个人使用习惯,可能我们还是比较习惯用windows.虽然说在wind ...

  8. java:练习学校学生

    java:练习学校学生 一个学生对应一个学校 一个学校对应多个学生 Student类,School类,Demo测试类 Student: public class Student { private S ...

  9. 验证reg注册表的操作

    // wRegKeyclass wRegKey{ // Operationspublic: BOOL Create(HKEY hKeyParent, LPCTSTR lpszKeyName , LPT ...

  10. leetcode 3 Longest Substring Without Repeating Characters(滑动窗口)

    用滑动窗口的思想来做.用一个unordered_map来查询之前的char有没有在现在的窗口中. class Solution { public: int lengthOfLongestSubstri ...