在六月,我们在博客上发布了一个新的内部状态机,用于管理用户,计时器和引擎线程之间的交互。 现在,我们对该代码进行了另一次大的内部清理,以使其更易于阅读和理解。

如前所述,所有操作(插入,更新,删除等)现在都放入线程安全传播队列中。 执行这些操作时,用户线程再也不会接触引擎,甚至Alpha网络也不会。 这样可以提高线程安全性。 相反,当引擎启动时,它首先排空并评估此队列,这可能导致在进行规则评估和触发之前进行alpha网络评估。

除了用户线程和引擎线程的分离之外,状态机的另一个目标是协调Timer线程。 当计时器启动时,发动机可能不起作用或正在运行。 如果引擎处于活动状态,则计时器应只向传播队列提交一个条目,并让当前执行的线程处理该作业。 如果引擎未处于活动状态并且计时器规则是异步的,则计时器线程应通过executeTask方法来进行评估和触发。 状态机旨在最小化同步和锁定,以使争用最小。

引擎现在可以处于5种可能的状态。INACTIVE是启动状态。

引擎评估和规则触发具有三个潜在的入口点fireAllRules,fireUntilHalt和异步计时器规则-后者是通过executeTask部分完成的。 我们将fireAllRules和fireUntilHalt统一到单个fireLoop方法中,该方法使用作为参数传递的策略类来处理循环的潜在休息状态。 如果没有规则触发,没有更多要评估的议程组以及队列为空,则认为引擎处于静止状态。

然后,FireAllRules所有规则会将引擎设置为INACTIVE,然后退出循环。 FireUntilHalt将使当前线程等待,直到更多工作进入队列进行处理。 这里已经进行了工作,以确保在这些状态转换期间没有间隙和执行损失。

当线程想要转换为FIRE_ALL_RULES或FIRE_UNTIL_HALT或EXECUTE_TASK时,它必须通过waitAndEnterExecutionState。 如果引擎为非活动状态,则可以立即转换,否则,将进入等待状态,直到当前执行线程完成并将引擎返回至非活动状态:

private void waitAndEnterExecutionState( ExecutionState newState ) {if (currentState != ExecutionState.INACTIVE) {try {stateMachineLock.wait();} catch (InterruptedException e) {throw new RuntimeException( e );}}setCurrentState( newState );
}

让我们看看fireAllRules()如何使用它。 首先请注意,如果引擎已经在运行,因为先前已调用fireAllRules或fireUntilHalt并仍在运行,则它将退出。 第二个注意事项是,它仅将同步点保持足够长的时间,以退出或进行所需的过渡。 一旦引擎进入FIRE_ALL_RULES状态,它就可以释放同步块,并且状态机将停止任何干扰。

public int fireAllRules(AgendaFilter agendaFilter,int fireLimit) {synchronized (stateMachineLock) {if (currentState.isFiring()) {return 0;}waitAndEnterExecutionState( ExecutionState.FIRING_ALL_RULES );}int fireCount = fireLoop(agendaFilter, fireLimit, RestHandler.FIRE_ALL_RULES);return fireCount;
}

fireLoop现在是通用的,并且由fireAllRules和fireUntilHalt共同使用,并使用RestHandler策略来处理引擎到达静止点时的逻辑。

private int fireLoop(AgendaFilter agendaFilter,int fireLimit,RestHandler restHandler) {// The engine comes to potential rest (inside the loop) when there are no propagations and no rule firings.        // It's potentially at rest, because we cannot guarantee it is at rest.        // This is because external async actions (timer rules) can populate the queue that must be executed immediately.        // A final takeAll within the sync point determines if it can safely come to rest.        // if takeAll returns null, the engine is now safely at rest. If it returns something        // the engine is not at rest and the loop continues.        //        // When FireUntilHalt comes to a safe rest, the thread is put into a wait state,        // when the queue is populated the thread is notified and the loop begins again.        //        // When FireAllRules comes to a safe rest it will put the engine into an INACTIVE state        // and the loop can exit.        //        // When a halt() command is added to the propagation queue and that queue is flushed        // the engine is put into a HALTING state. At this point isFiring returns false and        // no more rules can fire and the loop exits.int fireCount = 0;try {PropagationEntry head = workingMemory.takeAllPropagations();int returnedFireCount = 0;boolean limitReached = fireLimit == 0; // -1 or > 0 will return false. No reason for user to give 0, just handled for completeness.boolean loop = true;while ( isFiring()  )  {if ( head != null ) {// it is possible that there are no action propagations, but there are rules to fire.                this.workingMemory.flushPropagations(head);head = null;}// a halt may have occurred during the flushPropagations,            // which changes the isFiring state. So a second isFiring guard is needed            if (!isFiring()) {break;}evaluateEagerList();InternalAgendaGroup group = getNextFocus();if ( group != null && !limitReached ) {// only fire rules while the limit has not reached.returnedFireCount = fireNextItem( agendaFilter, fireCount, fireLimit, group );fireCount += returnedFireCount;limitReached = ( fireLimit > 0 && fireCount >= fireLimit );head = workingMemory.takeAllPropagations();} else {returnedFireCount = 0; // no rules fired this iteration, so we know this is 0                group = null; // set the group to null in case the fire limit has been reached            }if ( returnedFireCount == 0 && head == null && ( group == null || !group.isAutoDeactivate() ) ) {// if true, the engine is now considered potentially at rest                head = restHandler.handleRest( workingMemory, this );}}if ( this.focusStack.size() == 1 && getMainAgendaGroup().isEmpty() ) {// the root MAIN agenda group is empty, reset active to false, so it can receive more activations.            getMainAgendaGroup().setActive( false );}} finally {// makes sure the engine is inactive, if an exception is thrown.        // if it safely returns, then the engine should already be inactive// it also notifies the state machine, so that another thread can take over        immediateHalt();}return fireCount;
}

fire循环在执行takeAll()时会经过单个同步点,这是返回当前head实例的简单操作,同时还使成员head字段为空,从而使队列为空。 在此takeAll()期间,这意味着任何用户或计时器操作都必须等待同步释放后才能添加到队列中。 在执行完其余方法之后,可以执行评估返回的项目列表以及评估网络和触发规则的过程,而无需进行另一个同步或锁定。

其余处理程序都是两个非常简单的代码段:

interface RestHandler {RestHandler FIRE_ALL_RULES = new FireAllRulesRestHandler();RestHandler FIRE_UNTIL_HALT = new FireUntilHaltRestHandler();PropagationEntry handleRest(InternalWorkingMemory wm, DefaultAgenda agenda);class FireAllRulesRestHandler implements RestHandler {@Override        public PropagationEntry handleRest(InternalWorkingMemory wm, DefaultAgenda agenda) {synchronized (agenda.stateMachineLock) {PropagationEntry head = wm.takeAllPropagations();if (head == null) {agenda.halt();}return head;}}}class FireUntilHaltRestHandler  implements RestHandler {@Override        public PropagationEntry handleRest(InternalWorkingMemory wm, DefaultAgenda agenda) {return wm.handleRestOnFireUntilHalt( agenda.currentState );}}
}@Overridepublic PropagationEntry handleRestOnFireUntilHalt(DefaultAgenda.ExecutionState currentState) {// this must use the same sync target as takeAllPropagations, to ensure this entire block is atomic, up to the point of wait    synchronized (propagationList) {PropagationEntry head = takeAllPropagations();// if halt() has called, the thread should not be put into a wait state        // instead this is just a safe way to make sure the queue is flushed before exiting the loop        if (head == null && currentState == DefaultAgenda.ExecutionState.FIRING_UNTIL_HALT) {propagationList.waitOnRest();head = takeAllPropagations();}return head;}
}

请注意,FireAllRulesRestHandler必须在执行最后的takeAll时获取stateMachineLock,然后才能知道它真正安全地返回。 这是由于可能放置在队列中的计时器需要立即触发。 如果要返回引擎,计时器将不会立即触发-这就是我们所说的行为“差距”,现在可以避免。

FireUntilHalt锁定了传播队列,因为除了执行takeAll之外,它还必须原子地执行空值检查和等待操作。 再一次,如果空检查不在同步点之内,我们最终会在行为上出现另一个潜在的差距,现在可以避免这种情况。

难题的最后一部分是executeTask。 这允许以最佳方式发生异步操作(通常是计时器任务)。 如果引擎由于FireAllRules或FireUntilHalt而已经在运行,则只需将任务提交到队列中,然后让当前运行的线程来处理它。 如果不是,则进入EXECUTING_TASK状态并在当前线程中执行它。

@Overridepublic void executeTask( ExecutableEntry executable ) {synchronized (stateMachineLock) {// state is never changed outside of a sync block, so this is safe.        if (isFiring()) {executable.enqueue();return;} else if (currentState != ExecutionState.EXECUTING_TASK) {waitAndEnterExecutionState( ExecutionState.EXECUTING_TASK );}}try {executable.execute();} finally {immediateHalt();}
}

我应该补充说,halt()现在作为命令提交,并作为标准队列消耗的一部分进行评估。 执行时,它将在同步块内将引擎更改为暂停状态。 这将允许外部循环退出:

public void halt() {synchronized (stateMachineLock) {if (currentState.isFiring()) {setCurrentState( ExecutionState.HALTING );}}
}

因此,我们现在有了真正健壮的代码,可以以可理解的方式处理用户,计时器和引擎线程的交互。 我们在清理中付出了很多努力,以便希望每个人都能理解代码和行为。

发动机的最后一部分仍然被认为是不安全的。 在引擎运行时,用户可以在此在一个线程上调用插入事实的设置方法。 这显然可以流下眼泪。 我们计划允许用户将任务提交到此队列,以便可以使用与正在运行的引擎相同的线程来执行任务。 这将允许用户从引擎外部的另一个线程提交pojo更新,作为任务来安全执行。

翻译自: https://www.javacodegeeks.com/2015/12/drools-detailed-description-internal-code-cleanups-fireallrules-fireuntilhalt-timers.html

Drools:fireAllRules,fireUntilHalt和Timers内部代码清理的详细说明相关推荐

  1. drools。drools_Drools:fireAllRules,fireUntilHalt和Timers内部代码清理的详细说明

    drools.drools 在六月,我们在博客上发布了一个新的内部状态机,用于管理用户,计时器和引擎线程之间的交互. 现在,我们对该代码进行了另一次大的内部清理,以使其更易于阅读和理解. 如前所述,所 ...

  2. 内部代码显示苹果iOS 15.5 Beta新增支持外部链接支付

    4月7日消息,据国外媒体报道,内部代码显示,在iOS 15.5 Beta版中,"阅读器"应用程序增加了外部支付渠道的支持. 在与监管机构进行长时间的斗争之后,如今苹果将在最新操作系 ...

  3. @程序员,代码清理有必要吗?

    [CSDN编者按]日常编程工作中,程序员经常面临各种代码bug.但是是否所有项目都适合清理重构?bug修复的手段又是否合理?本文的作者以原型设计.新项目.紧急bug修复.新功能开发.项目维护等各阶段为 ...

  4. java中cleanup的使用_Eclipse使用代码清理功能(Clean Up)

    本文转载自http://www.ibm.com/developerworks/cn/opensource/os-eclipse-clean/ 但是为了适应自己使用,还是自己总结了一下. 一.概述 代码 ...

  5. Linux用代码清理磁盘缓存(运行时清理磁盘缓存)

    Linux用代码清理磁盘缓存(运行时清理磁盘缓存) 文章目录 Linux用代码清理磁盘缓存(运行时清理磁盘缓存) 基础:命令行清除缓存 清理缓存的命令行命令 原理 实践:程序运行过程中(以代码方式)释 ...

  6. Simens NX (原UG)内部代码逆向分析 / Inner code Reverse analysis of NX software

    [篇首语]这里的逆向分析不是机械中的反求工程(抄数),而是软件中的逆向工程,旨在研究软件内部代码实现机制.我在这里要说明一下,软件逆向不在软件使用的许可范围之内,仅可以作为研究软件实现功能的一种方法. ...

  7. 企业安全之内部代码管理平台Gitlab下载及权限审计

    企业通常会使用Gitlab作为内部代码管理平台,一来私有仓库更加安全,二来gitlab的功能十分完整.但仍不能保证私有仓库中的代码不被泄露到外部,于是对gitlab的权限审计以及下载审计就变得尤为重要 ...

  8. 归并排序(代码注释超详细)

    归并排序: (复制粘贴百度百科没什么意思),简单来说,就是对数组进行分组,然后分组进行排序,排序完最后再整合起来排序! 我看了很多博客,都是写的8个数据呀什么的(2^4,分组方便),我就想着,要是10 ...

  9. 400 多行代码!超详细 Rasa 中文聊天机器人开发指南 | 原力计划

    作者 | 无名之辈FTER 责编 | 夕颜 出品 | 程序人生(ID:coder_life) 本文翻译自Rasa官方文档,并融合了自己的理解和项目实战,同时对文档中涉及到的技术点进行了一定程度的扩展, ...

最新文章

  1. 小晶粒zsm分子筛合成表征实验报告_Nat. Mater.:区域选择性合成亚纳米金属-分子筛材料...
  2. Pymol | Pymol绘制GridBox图
  3. 递归算法经典实例_掌握这10道经典面试算法题(含答案),攻克递归算法【程序员必备】...
  4. pip安装包时遇到的Bug
  5. linux变量inode,linux字符cdev和Inode的关系
  6. Python看似简单的地方——关于全局变量与局部变量
  7. activeMQ使用总结
  8. ionic2 mac android,Ionic制作Hybrid App系列二:Mac环境下Ionic release版本APK的签名与发布...
  9. 如何在Java中对文件进行模式匹配和显示相邻行
  10. 特斯拉上海超级工厂已在建设动力系统厂房
  11. 利用vSAN Performance Monitor可视化监控vSAN性能指标
  12. 跟着辛星用PHP的反射机制来实现插件
  13. NLP、CV、语音相关AI算法工程师面试问题、代码、简历模板、知识点等资源整理分享
  14. 8.25 ccpc 比赛总结
  15. Win7系统文件缺失怎么修复
  16. php中fastcgi和php-fpm是什么
  17. 0x80004005是什么错误?0x80004005的解决方案
  18. 近邻成分分析(NCA)算法
  19. 独立开发者:我为什么要学游戏编程?
  20. DSB2017第一名代码复现

热门文章

  1. java之String
  2. 【Mysql】win10上Mysq的l安装
  3. 19年8月 字母哥 第四章 常用web开发数据库框架 不要用公司网络加载不出来 用热点!!!
  4. php 向html追加元素,在PHP中存储兄弟元素的属性和内部HTML
  5. java泛型程序设计——Varargs 警告+不能实例化类型变量
  6. r2dbc_使用Spring Data R2DBC进行异步RDBMS访问
  7. 用jackson转json_用Jackson编写大JSON文件
  8. lineseparator_首选System.lineSeparator()以用Java编写系统相关的行分隔符字符串
  9. tibco汉化包6.3.0_TIBCO BusinessWorks 6和Container Edition与BW5的比较
  10. jax-rs jax-ws_如何以大数据的JAX-RS响应的形式将JPA结果流化/序列化