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

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

如前所述,所有操作(插入,更新,删除等)现在都放入线程安全传播队列中。 执行这些操作时,用户线程再也不会接触引擎,甚至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之外,它还必须原子地执行空值检查和等待操作。 再一次,如果空检查不在同步点之内,我们最终会在行为上出现另一个潜在的差距,现在可以避免这种情况。

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

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

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

相关文章

BZOJ 4517 组合数+错排

思路&#xff1a; 预处理错排 然后C(n,m)*s[n-m-1]就是答案了 特判n-m-1<0 //By SiriusRen #include <cstdio> using namespace std; #define int long long const int mod1000000007,N1000050; int cases,n,m,fac[N],s[N]; int pow(int x,int y){int res1;while(y){i…

鸿蒙os下载到电脑上,鸿蒙系统pc版下载2.0

鸿蒙系统pc版2.0是华为最新打造的系统&#xff0c;采用分布式操作系统&#xff0c;可以在华为各种设备上使用。华为鸿蒙2.0系统pc版可以适应全新的芯片&#xff0c;打造个性化的操作习惯&#xff0c;可以让用户使用更舒适&#xff0c;功能更强大。它是一个面向全场景的开源分布…

nodejs+vue+ElementUi房屋房产销售预约看房系统bqv00

完成房产销售系统&#xff0c;对房源的信息、用户信息及各种资料进行收集和科学的管理&#xff0c;该系统的功能基本可以满足当前市面上的小型房产企业对于房产销售的基本要求&#xff0c;收集各个地区的房源信息并进行分类管理&#xff0c;用户通过注册账号登录网站查询房源信…

16.条件控制语句

11.关于条件控制和语句&#xff0c;流程控制语句if...else 1)语法&#xff1a; 第一种结构&#xff1a; if(boolean表达式){ java语句&#xff1b; } 第二种结构&#xff1a; if(boolean表达式){ java语句; }else{ java语句; } 第三种结构&#xff1a; if(boolean表达式){ java…

使用Chameleon,Shrinkwrap,Drone / Graphene与Arquillian进行Java EE集成测试

从我以前的帖子继续在这里 &#xff0c;我想我已经了解了Java EE和也的Arquillian&#xff0c;并测试了一些新的&#xff08;和令人兴奋的&#xff09;事&#xff0c;我想与大家分享。 但是&#xff0c;在开始之前&#xff0c;我想首先请您注意以下几点&#xff08;这些纯粹是…

mysql配置以及性能优化(转)

MySQL配置文件my.cnf中文详解&#xff0c;附mysql性能优化方法分享 Mysql参数优化对于新手来讲&#xff0c;是比较难懂的东西&#xff0c;其实这个参数优化&#xff0c;是个很复杂的东西&#xff0c;对于不同的网站&#xff0c;及其在线量&#xff0c;访问量&#xff0c;帖子数…

android+完美的列表,android完美讲义.pdf

android完美讲义王骋QQPhoneMail• 感谢我的同事&#xff0c;陈操(横拓开源技术副总)&#xff0c;在他提供的资料乊上做了迚一步总结提炼。• 参考资料android sdk开发文档&#xff0c;IBM开发者&#xff0c;同时也感谢网络上的各位大侠• 这个ppt更多是总结&#xff0c;侧重亍…

ios framework 找不到.h_找不到好看的壁纸?上万张「高清壁纸」,都在iOS捷径里...

所需工具&#xff1a;iOS捷径获取方法&#xff1a;后台私信回复「363」不和大家废话&#xff0c;今天给大家分享一个超好用的ios壁纸捷径&#xff0c;用了它之后再也不怕找不到喜欢的壁纸了~将克拉壁纸的捷径链接在Safari浏览器打开&#xff0c;就会自动跳转到一个获取捷径的窗…

12306余票查询

https://kyfw.12306.cn/otn/leftTicket/queryX?leftTicketDTO.train_date2017-04-02&leftTicketDTO.from_stationHXZ&leftTicketDTO.to_stationIZQ&purpose_codesADULT 转载于:https://www.cnblogs.com/jekaysnow/p/6657918.html

div内容用html语言写,html – 使用DIV作为另一个元素的背景

这里我用2个div做了一个例子&#xff1a;> .content,包含前端所需的一切> .background – 包含文本,图像和背景中的所有其他内容要将一个div包装在另一个div上(制作叠加层),你必须将它们放入相同的元素中,在本例中它是#wrapper div.放置位置&#xff1a;包装的相对宽度/高…

jetty 配置jndi_使用Jetty设置JNDI(嵌入式)

jetty 配置jndi我在开发工作区上运行嵌入式Jetty&#xff0c;从而节省了一些恶性的编译和部署周期。 我与Jetty的合作不多&#xff0c;易用性使我着迷于它。 我需要设置JNDI才能检索与数据库相关的活动的连接池。 尽管某些地方有完整的文档&#xff0c;但大多数都是分散的。 因…

auot lisp 选择集处理_离散量的计算机处理63_1Cv6

计算机语言运用--数值计算6-离散量的计算机处理63_1Cv6计算机&#xff1a;电子线路组成的计算机器。人与计算机则是通过计算机语言-符号系统说给计算机听而交流。计算机语言有低级语言-机器语言、汇编、高级语言-C/C/C#/VB/PASCAL/LISP/JAVA/PYTHON/……成百上千种之多。作为一…

bzoj 3928: [Cerc2014] Outer space invaders

$f[i][j]$表示消灭起始时间在$(i,j)$内的外星人所花费的最小代价。 考虑在这个区间内距离最远的外星人h&#xff0c;在他的区间中一定要选一个点要开一炮&#xff0c;而且这一炮可以顺便把其他跨过这个点的敌人消灭&#xff0c;剩下只需消灭没有跨过这个点的敌人。 枚举开炮时间…

HTML页面代码移动端和pc兼容,pc端网站如何实现移动端适配?

4、流动布局(fluidgrid)“流动布局”的含义是&#xff0c;各个区块的位置都是浮动的&#xff0c;不是固定不变的。.main{float:right;width:70%;}.leftBar{float:left;width:25%;}float的好处是&#xff0c;如果宽度太小&#xff0c;放不下两个元素&#xff0c;后面的元素会自动…

linkedblockingqueue 后 take 不消化_消化不良的成因及护理

疾病名称&#xff1a;消化不良就诊科室&#xff1a;消化内科疾病成因心理和精神的不良应激&#xff1a;患者的精神不愉快、长期闷闷不乐或突然受到猛烈的刺激等均可引起。不良饮食习惯&#xff1a;包括刺激性食物&#xff08;咖啡、浓茶、甜食、油腻、生冷等&#xff09;和不良…

功能与命令式编程。 Java 8中的斐波那契,素数和阶乘

有多种编程风格/范例&#xff0c;但是两种著名的风格是Imperative和Functional 。 命令式编程是最主要的范例&#xff0c;因为几乎所有主流语言&#xff08;C &#xff0c;Java&#xff0c;C&#xff03;&#xff09;都在推广它。 但是在最近几年中&#xff0c;函数式编程开始…

Yandex.Algorithm 2011 Round 2 D. Powerful array 莫队

题目链接&#xff1a;点击传送D. Powerful arraytime limit per test5 secondsmemory limit per test256 megabytesinputstandard inputoutputstandard outputAn array of positive integers a1, a2, ..., an is given. Let us consider its arbitrary subarray al, al  …

html 形状div,div+css实现各种形状(精心整理)

1.正方形.div {width: 100px;height: 100px;background: red;}2.矩形.div {width: 200px;height: 100px;background: red;}3.圆形.div {width: 100px;height: 100px;background: red;-moz-border-radius: 50px;-webkit-border-radius: 50px;border-radius: 50px;}4.椭圆.div {w…

4.1.5事件

用事件有一种监听的思想 一个事件对应一个委托 事件是委托类型 一个事件对应一个委托&#xff0c;委托可以对应多个方法 如气球爆炸了 气球的反应 小孩的反应 事件源有代码自动激发事件 扔出事件 —————————————— 3.只能在类的内部触发事件 4.可以在内部…

485不用双绞线可以吗_现在在上海,挡风玻璃可以一个标志都不用贴吗?

问近日&#xff0c;有市民咨询&#xff1a;现在在上海&#xff0c;车上挡风玻璃可以一个标志都不用贴吗&#xff1f;答可以一个标志都不贴。自2020年3月1日起&#xff0c;本市机动车在本市办理注册、变更、转移登记和核发检验标志、补换检验标志业务时&#xff0c;将自动生成检…