2013-01-08 198 views
2

我的应用程序处理多个请求,但我的知识会话中的规则仅由单线程执行。 例如: 线程1和线程2进入知识会话的间隙为2millisec 但是线程1执行自己的规则,甚至线程2的规则都由线程1执行。想象一下,如果有1000个请求意味着每个请求的规则将仅由1个线程执行?在DROOLS中执行单线程?

有没有什么方法可以在DROOLS中防止这种情况,并确保规则由多个线程执行?

下面是一个小样本的测试,我试过:

的Java类:

 import java.math.BigDecimal; 

     import org.drools.KnowledgeBase; 
     import org.drools.KnowledgeBaseFactory; 
     import org.drools.builder.KnowledgeBuilder; 
     import org.drools.builder.KnowledgeBuilderError; 
     import org.drools.builder.KnowledgeBuilderErrors; 
     import org.drools.builder.KnowledgeBuilderFactory; 
     import org.drools.builder.ResourceType; 
     import org.drools.io.ResourceFactory; 
     import org.drools.runtime.StatefulKnowledgeSession; 
import org.drools.runtime.rule.WorkingMemoryEntryPoint; 
import org.springframework.context.support.ClassPathXmlApplicationContext; 



     public class DJ_Test { 

      public static void main(String[] args) { 
       try { 
        System.out.println("In main"); 
        // load up the knowledge base 
        KnowledgeBase kbase = readKnowledgeBase(); 
        final StatefulKnowledgeSession ksession = kbase.newStatefulKnowledgeSession(); 
        final WorkingMemoryEntryPoint entry =ksession.getWorkingMemoryEntryPoint("RequestStream"); 

        final Object obj_1= new Object(); 
        Thread t1 = new Thread(){ 
         public void run(){System.out.println(Thread.currentThread().getName() + " is running"); 
         entry.insert(obj_1); 
         ksession.fireAllRules(); 
         System.out.println(Thread.currentThread().getName() + " is terminated"); 
         } 
         }; 

        final Object obj_2= new Object(); 
        Thread t2 = new Thread(){ 
        public void run(){ 
        try{ 
         Thread.sleep(8000); 
        }catch(Exception e){ 

        } 
        System.out.println(Thread.currentThread().getName() + " is running"); 
        entry.insert(obj_2); 
        ksession.fireAllRules(); 
        System.out.println(Thread.currentThread().getName() + " is terminated"); 
        } 
        }; 
        t1.start(); 
        t2.start(); 





       } catch (Throwable t) { 
        t.printStackTrace(); 
       } 
      } 

      private static KnowledgeBase readKnowledgeBase() throws Exception { 
       /* KnowledgeBuilder kbuilder = KnowledgeBuilderFactory.newKnowledgeBuilder(); 
       kbuilder.add(ResourceFactory.newClassPathResource("rulesFlow.bpmn"), ResourceType.BPMN2); 
       kbuilder.add(ResourceFactory.newClassPathResource("KansasSalesTax.drl"), ResourceType.DRL); 
       kbuilder.add(ResourceFactory.newClassPathResource("MissouriSalesTax.drl"), ResourceType.DRL); 
       kbuilder.add(ResourceFactory.newClassPathResource("SalesTax.drl"), ResourceType.DRL); 
       KnowledgeBuilderErrors errors = kbuilder.getErrors(); 
       if (errors.size() > 0) { 
        for (KnowledgeBuilderError error: errors) { 
         System.err.println(error); 
        } 
        throw new IllegalArgumentException("Could not parse knowledge."); 
       } 
       KnowledgeBase kbase = KnowledgeBaseFactory.newKnowledgeBase(); 
       kbase.addKnowledgePackages(kbuilder.getKnowledgePackages()); 
       return kbase;*/ 
       ClassPathXmlApplicationContext serviceContext = new ClassPathXmlApplicationContext("droolsContext.xml"); 
       return (KnowledgeBase) serviceContext.getBean("kbase1"); 
      } 

      public static class DJ_Message { 

       public static final int thread_1 = 1; 
       public static final int thread_2 = 2; 

       private String message; 

       private int status; 

       public String getMessage() { 
        return this.message; 
       } 

       public void setMessage(String message) { 
        this.message = message; 
       } 

       public int getStatus() { 
        return this.status; 
       } 

       public void setStatus(int status) { 
        this.status = status; 
       } 

      } 

     } 

DRL文件

package com.sample 

import com.sample.DroolsTest.Message; 

//global CepService cepService; 
declare Object 
    @role(event) 
end 


rule "rule_1" 
salience 100 
    when 
     $o : Object() from entry-point RequestStream 
    then 
     System.out.println("Rule 1 fired by " + Thread.currentThread().getName()); 
     Thread.sleep(5000); 

end 


rule "rule_2" 
salience 80 
    when 
     $o : Object() from entry-point RequestStream 
    then 
     System.out.println("Rule 2 fired by " + Thread.currentThread().getName()); 
     Thread.sleep(5000); 

end 

rule "rule_3" 
salience 60 
    when 
     $o : Object() from entry-point RequestStream 
    then 
     System.out.println("Rule 3 fired by " + Thread.currentThread().getName()); 
     //cepService.executingThread1(); 
end 

rule "4" 
    when 
     Message(status == Message.GOODBYE, myMessage : message) 
    then 
     System.out.println(myMessage); 
     //cepService.executingThread2(); 
end 

回答

1

StatefulKnowledgeSession s的根据不是线程安全的API docs。如果您绝对需要在多个线程上执行规则,请改为使用StatelessKnowledgeSession s重新表达您的问题。

+0

嗯,这不是人们要求调用的方法,而是返回所有活动会话,不是一个新的。 – nlucaroni

1

您可以在多线程环境中使用有状态知识会话。在您的应用程序启动之前,您必须将“知识库”序列化为文件/数据库“。稍后,每个线程将不会创建自己的”知识库“副本,但会从”文件/数据库“序列化”知识库“。如果我们不序列化/反序列化“KnowledgeBase”,则每个线程在需要时将尝试加载规则并创建自己的“KnowledgeBase”,最后在线程增加您的应用程序时最终可能会抛出“java.lan.OutOfMemory permgen”因为每个线程都会尝试通过一次又一次地将类加载到内存中来创建自己的知识库副本