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

drools。drools

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

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

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

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

8天

引擎评估和规则触发具有三个潜在的入口点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之外,它还必须原子地执行null检查和等待操作。 再一次,如果空检查不在同步点之内,我们将在行为上产生另一个潜在的差距,现在可以避免这种情况。

难题的最后一部分是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。drools

本文来自互联网用户投稿,该文观点仅代表作者本人,不代表本站立场。本站仅提供信息存储空间服务,不拥有所有权,不承担相关法律责任。如若转载,请注明出处:http://www.mzph.cn/news/336622.shtml

如若内容造成侵权/违法违规/事实不符,请联系多彩编程网进行投诉反馈email:809451989@qq.com,一经查实,立即删除!

相关文章

云服务器文件打包,云服务器文件打包

云服务器文件打包 内容精选换一换Winscp无法连接到服务器。SSH连接工具例如Xshell可以正常连接云服务器。其他SSH工具连接云服务器正常,但是Winscp无法连接到服务器。说明SSH服务是没有问题的,Winscp连接基于的是SFTP协议。查看/etc/ssh/sshd_config文件…

完全复制一个dict_Redis主从复制getshell技巧

Redis未授权漏洞常见的漏洞利用方式:Windows下,绝对路径写webshell 、写入启动项。Linux下,绝对路径写webshell 、公私钥认证获取root权限 、利用contrab计划任务反弹shell。基于Redis主从复制的机制,可以完美无损的将文件同步到…

pcl_openmap_OpenMap教程3 –使用MapHandler构建基本的地图应用程序–第2部分

pcl_openmap1.简介 在上一教程中,我们了解了MapHandler如何将各种组件连接在一起(更具体地说,是从MapHandlerChild派生的类)。 我们看到了如何以编程方式执行此操作,但是还有另一种声明性地使用openmap.properties 。 …

xy轴坐标图数字表示_【相机标定】四个坐标系之间的变换关系

点击上方“新机器视觉”,选择加"星标"或“置顶”重磅干货,第一时间送达世界坐标系,相机坐标系,图像物理坐标系,像素坐标系之间的关系:首先看下几个坐标系在放在一块的样子:1&#xff…

设计模式的Java 8 Lambda表达式-策略设计模式

策略模式定义封装在通常称为Context的驱动程序类中的一系列算法,并使这些算法可互换。 它使算法易于互换,并提供了在特定时间选择适当算法的机制。 算法(策略)在运行时由客户端或上下文选择。 在与客户端交互期间,Con…

调用打印机_涨知识|你不知道的关于打印机的打印过程和打印机驱动的那些事...

以前一直以为打印很简单,不就是编辑好文件按个“打印”就行了?但其实打印过程可以复杂到你分分钟“怀疑人生”。你以为的打印过程可能是这样的 ↓。我们看到的打印过程然而,真正的打印过程是这样的 ↓。实际上的打印过程打印机打印一页文件或…

kite 使用 go_使用Apache Storm和Kite SDK Morphlines的可配置ETL处理

kite 使用 go从我担任软件工程师的第一天起,我总是听到很多方面的相同要求: “ 我们希望所有内容都可配置,我们希望在运行时更改所有内容,我们希望有一个可视化工具来应用所有这些逻辑,以便非开发人员使用和配置我们的…

使用react实现select_使用 Hooks 优化 React 组件

奇技指南本文内容主要是我之前分享的文字版,若想看重点的话可以看之前的Slide: https://ppt.baomitu.com/d/75fc979a本文作者奇舞团前端开发工程师李喆明。需求描述由于作者所在的业务是资讯内容类业务,因而在业务中会经常碰到如下场景:有一个…

cacti不能实时刷新流量图_介绍一种编码帧内刷新算法

0.引言本文主要介绍一种帧内刷新算法,解决I帧太大带来的延迟问题,可以在调优时,值得借鉴。帧内刷新技术避免 I 帧尖峰带来的带宽压力,可以有效地降低视频通信中的缓冲区延迟。帧内刷新算法是一种视频错误恢复的方法,通…

按钮自动居中布局_CSS布局技巧

css实现左右布局和居中布局显示是前端进行页面设计的基础,也是全面了解并学习css一个很好的切入点,因为其中会涉及到对许多css基础点的认知。实现css入门,理解左右布局的实现方式是必经之路,同时也能使我们在项目中涉及前端编码的…

jooq_jOOQ星期二:拉斐尔·温特豪德(Rafael Winterhalter)正在与字节好友合作字节码...

jooq欢迎来到jOOQ Tuesdays系列。 在本系列文章中,我们每隔一个月的第三个星期二发布一篇文章,从jOOQ的角度采访我们发现该行业令人兴奋的人。 这包括从事SQL,Java,开放源代码以及各种其他相关主题的人员。 我们很高兴在第七版中…

多方法接口回调_啊?Java反射遇到接口

本文适合有点Java反射基础的同学,在Java反射调用方法时遇到接口参数是一件很蛋疼的事情。在反射调用方法时需要传参数,像传递基本数据类型进去用就完事,传个对象进去怎么整都没关系,因为你在外部有对象的引用,但 如果需…

0与1世界的初级编程篇之C语言

C语言是一门面向过程的计算机编程语言,与C、Java等面向对象编程语言有所不同。C语言的设计目标是提供一种能以简易的方式编译、处理低级存储器、仅产生少量的机器码以及不需要任何运行环境支持便能运行的编程语言。C语言描述问题比汇编语言迅速,工作量小…

QT 手动创建信号函数 与 槽函数

自定义信号槽必须要有Q_OBJCT 自己通过关键字signals创建信号函数,只声明信号函数即可,系统会自动定义它。 利用 public slots: 声明一个槽函数,槽函数不会自动生成,并且去定义它。

九九乘法表代码口述_利用随机函数实现座次表的随机排座

昨天听完讲座,晚上忍不住写了份学后感,今天有老师在文章下留言问如何实现随机排座,上午在快速理赔中心处理交通事故,处理完后将车开去4S店维修,回来后给娃做完中饭就开始写代码实现这个功能,因为有C功底&am…

jep使用_JEP 277“增强弃用”非常好。 但这是一个更好的选择

jep使用维护API很难。 我们正在维护非常复杂的jOOQ API。 但是就语义版本而言,我们遵循相对宽松的规则 。 当您阅读Brian Goetz和其他人关于在JDK中保持向后兼容性的评论时,我只能对他们的工作表示敬意。 显然,我们都希望最终移除Vector &a…

古巴比伦乘法_古巴平台中的通用过滤器–类固醇上的excel过滤器

古巴比伦乘法正如我上次承诺的那样,我计划浏览该平台的某些功能,这些功能我认为非常有价值。 所以我将在这里做一些系列。 从明显的用户界面,过滤,安全性到一些高级功能(如Web Portal,可扩展性,…

excel运行没反应_Excel数据很少文件却很大,问题出在哪里呢?两种方法轻松解决...

经常和Excel打交道的小伙伴可能会有这样的困惑,一个Excel工作簿中的数据明明很少,文件所占的空间却很大。打开这种Excel工作簿后,电脑CPU占用率瞬间飙升,甚至遇见工作簿没有响应的情况出现。遇见这样的工作簿让人窝火,…

java lambda::_基准测试:Java 8 Lambda和流如何使您的代码慢5倍

java lambda::与长期的实现相比,Java 8 lambda和流的性能如何? Lambda表达式和流在Java 8中受到了热烈的欢迎。这些是迄今为止很激动人心的功能,很长一段时间以来,它们就已经应用到Java中了。 新的语言功能使我们可以在代码中采用…

如何在java中实现小数点自增_java编个计算器怎么在加入小数点

展开全部我做的可以运行,你看看吧!import java.awt.*;import java.awt.event.*;import java.lang.*;import javax.swing.*;public class Counter extends Frame{//声明三个面板的布局GridLayout gl1,gl2,gl3;Panel p0,p1,p2,p3;JTextField tf1;TextField…