2013-01-08 236 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」因爲每個線程都會嘗試通過一次又一次地將類加載到內存中來創建自己的知識庫副本