如何对运行正则表达式的java函数设置时间限制

如何对运行正则表达式的java函数设置时间限制,java,multithreading,Java,Multithreading,我在java函数中运行一个正则表达式来解析一个文档,如果它找到了正则表达式指定的字符串,则返回true;如果没有找到,则返回false。但问题是,当文档不包含正则表达式指定的字符串时,返回false需要很长时间,如果执行该函数需要6秒以上,我希望终止该函数 如何设置该功能的6秒时限,以便在超过6秒时强制终止该功能 我正在从类1调用类2的方法“方法1”。“方法1”调用同一类的“方法2”,即“类2”。方法2在文档上运行正则表达式代码。如果它找到正则表达式指定的字符串,那么它将结果返回给方法1,方法1

我在java函数中运行一个正则表达式来解析一个文档,如果它找到了正则表达式指定的字符串,则返回true;如果没有找到,则返回false。但问题是,当文档不包含正则表达式指定的字符串时,返回false需要很长时间,如果执行该函数需要6秒以上,我希望终止该函数

如何设置该功能的6秒时限,以便在超过6秒时强制终止该功能

我正在从类1调用类2的方法“方法1”。“方法1”调用同一类的“方法2”,即“类2”。方法2在文档上运行正则表达式代码。如果它找到正则表达式指定的字符串,那么它将结果返回给方法1,方法1将结果返回给“类1”中的方法,该方法调用类2的“方法1”。 现在的问题是类2的method1和method2的执行时间都不应该超过6秒

因此,我在同一个文件中创建了一个新的RegexpThread类,其中包含我的class2。然后我将类2的method2移动到类RegexpThread中。然后,每当调用方法1时,它都会实例化RegexpThread类,如下所示:

RegexpThread rt = new RegexpThread() {
    public void run() {
        method 2(m, urlCopy, document);
    }    
};

rt.start();

try {
    rt.join(6 * 1000);
} catch (InterruptedException e) {
    return "y";
}

if(rt.getResultXml().equals("")) {
    return "g";
}

resultXml.append(rt.getResultXml());

return resultXml.toString();
显示的代码在class2的方法1中。RegexpThread类中的方法2对文档执行一些正则表达式搜索。RegexpThread类中有一个名为“resultXml”的私有字段。如果方法2找到了正则表达式指定的字符串,那么它将结果分配给私有字段“resultXml”。如果不是,则“resultXml”包含其默认值,即空字符串

因此,在上面的“if块”中,它将根据空字符串检查“resultXml”字段。如果是空字符串,则表示正则表达式在文档中未找到其字符串。但如果它不是空字符串,则表示正则表达式已在文档中找到该字符串,并已将结果分配给“resultXml”字段


那么,看看这个,告诉我该怎么做…

通过执行器服务启动线程并给它一个超时,如下所示:

ExecutorService pool = Executors.newFixedThreadPool(POOL_SIZE);
pool.execute(rt);
pool.awaitTermination(timeout, timeUnit);
将等待任务完成(以及此
ExecutorService
下的所有其他任务),线程被中断,或出现超时(以先到为准)


听起来这很适合您的需要。

您没有显示实际执行正则表达式的函数,因此我假设它从文件中读取行并在每行上执行正则表达式

如果是这种情况,那么更好的解决方案是将超时值传递给该函数。在每N行之后(不管N是什么),它检查超时值


您将遇到的真正问题是阻塞IO—例如,从网络读取。在这种情况下,您无法从Java执行任何操作,因为阻塞实际上发生在操作系统内核中。

您所做的对我来说很好,下面是我如何修改它的:

final AtomicReference<String> resultXml = new AtomicReference<String>();

RegexpThread rt = new RegexpThread() {
  public void run() {
    method2(m, urlCopy, document, resultXml);
  }

};

rt.start();

try {
    rt.join(6 * 1000);
} catch (InterruptedException e) {
    return "y";
}

if(resultXml.get() == null) {
    rt.interupt();
    return "g";
}

resultXml.append(resultXml.get());

return resultXml.toString();
final AtomicReference resultXml=new AtomicReference();
RegexpThread rt=new RegexpThread(){
公开募捐{
方法2(m、urlCopy、文档、结果XML);
}
};
rt.start();
试一试{
rt.join(6*1000);
}捕捉(中断异常e){
返回“y”;
}
if(resultXml.get()==null){
rt.interupt();
返回“g”;
}
append(resultXml.get());
返回resultXml.toString();

这里我可能弄错了,但我认为所有终止线程的方法都是正确的。推荐的方法是使用一个共享的
isRunning
变量,工作线程会定期检查该变量,并在设置后正常退出


这在你的情况下不起作用,但在我看来,你在治疗症状,而不是真正的问题。您应该发布regexp函数的代码,执行该函数需要6秒钟。如果是regexp本身,那么执行时间可能是一个例子。

我现在假设您的regexp代码是正确的,它实际上是一些CPU限制为6秒的计算代码

鉴于上述情况,我认为你只有一个选择。在多个阶段/迭代中执行代码,并检查变量以请求暂停。您不能使用正常的
模式
/
匹配器
代码来执行此操作

您可以通过预先以某种方式分割输入字符串,然后一点一点地输入到regexp(初始分割必须独立于regexp)

您不能通过以下方式执行此操作:

  • 使用
    Thread.stop()
    等。这已被弃用,无法正常工作
  • 使用
    Thread.interrupt()
    。这将在线程上设置一个中断标志,该标志仅在线程执行IO时被检查。如果线程是CPU绑定的,则永远不会检查该标志

  • 鉴于上述情况,我将再次了解为什么regexp需要6秒才能匹配。regexp正确吗?您能在较小的文本段上执行regexp吗

    回答这个问题有两种方法

    一方面,没有一种实用/有效的方法可以安全地终止正在执行
    Matcher.find(…)
    Matcher.match(…)
    的线程。调用
    Thread.stop()
    可以工作,但存在严重的安全问题。解决这个问题的唯一方法是开发自己的正则表达式引擎,定期检查
    中断
    标志。(这并非完全不切实际。例如,如果GPL不是您的问题,您可以从OpenJDK中现有的正则表达式引擎开始。)

    另一方面,问题的真正根源(很可能)是您使用正则表达式的方式错误。要么你正试图做一些对单个正则表达式来说太复杂的事情,要么你的正则表达式是次优的

    编辑:正则表达式耗时过长的典型原因是多个量词(?,+)导致病理性回溯。例如,如果您尝试匹配N“a”cha字符串
    "(.*)<html>(.*)<head>(.*)</head>(.*)<body>(.*)</body>(.*)</html>(.*)"
    
    <html><html><html><html><html><html><html><html><html><html>
    <head><head><head><head><head><head><head><head><head><head>
    </head></head></head></head></head></head></head></head></head></head>
    <body><body><body><body><body><body><body><body><body><body><body>
    </body></body></body></body></body></body></body></body></body></body>
    
    @Timeable(limit = 1, unit = TimeUnit.SECONDS)
    String yourMethod() {
      // execution as usual
    }
    
    if (Thread.currentThread.isInterrupted()) {
      throw new IllegalStateException("time out");
    }
    
    package org.test.xpath;
    
    import java.util.regex.Matcher;
    import java.util.regex.Pattern;
    
    public class InterruptableMatcherTest {
    
        public static void main(String[] args) throws Exception{
    
            Pattern pattern=Pattern.compile("^(([a-z])+.)+[A-Z]([a-z])+$");
            String input="aaaaaaaaaaaaaaaaaaaaadddddddddddddddddddddddddddddddddddddddaaaaaaaaaaaa!";
    
            PatternMatcher patternMatcher=new PatternMatcher(pattern, input);
            Thread thread=new Thread(patternMatcher);
    
            thread.start();
    
            Thread.sleep(1*1000);
            System.out.println("Done sleeping ...");
            if(patternMatcher.running)patternMatcher.reset();//Without this call the program will hang
            thread.join();
    
        }//main closing
    
    }//class closing
    
    class PatternMatcher implements Runnable{
    
        Pattern pattern;
        Matcher matcher;
    
        boolean running=false;
    
        PatternMatcher(Pattern pattern, String input) {
    
            this.pattern=pattern;
            matcher=this.pattern.matcher(input);
    
        }//constructor closing
    
        @Override
        public void run() {
    
            running=true;
            matcher.matches();
            running=false;
    
        }//run closing
    
        void reset(){
    
            System.out.println("Reset called ...");
            matcher.reset("");
    
        }//reset closing
    
    }//class closing