I am running a regex in a java function to parse a document and return true if it has found the string specified by the regex and return false if it hasn\'t. But the problem
I will assume for the moment that your regexp code is correct, and it really is some computational code that is CPU-bound for 6s.
Given the above, I think you have only one option. To execute your code in a number of stages/iterations and check a variable for a request to halt. You can't do this using the normal Pattern
/Matcher
code.
You could do this by splitting your input string beforehand in some fashion, and then feeding to your regexp bit by bit (your initial split would have to be independent of your regexp).
You can't do this by:
Thread.stop()
etc. This has been deprecated and doesn't work properly.Thread.interrupt()
. This sets an interrupted flag on the thread which is only checked when the thread performs IO. If the thread is CPU-bound, then that flag will never be checked.Given the above, I would look again at why the regexp is taking 6s to match. Is the regexp correct ? Can you perform a regexp on smaller text segments ?
I might be mistaken here, but I think all ways to terminate a thread have been deprecated for some time. The recommended way is to use a shared isRunning
variable that your worker thread periodically checks and gracefully exits when it's been set.
This will not work in your case, but it looks to me like you're treating the symptom - not the real problem. You should post the code of your regexp function, that takes 6 seconds to execute. If it's the regexp itself, the execution time may be a case of catastrophic backtracking.
There are two ways to answer this question.
On the one hand, there is no practical/effective way that is known to be safe of killing a thread that is executing Matcher.find(...)
or Matcher.match(...)
. Calling Thread.stop()
would work, but there are significant safety issues. The only way to address this would be to develop your own regex engine that regularly checked the interrupted
flag. (This is not totally impractical. For example, if GPL wasn't an issue for you, you could start with the existing regex engine in OpenJDK.)
On the other hand, the real root of your problem is (most likely) that you are using regexes the wrong way. Either you are trying to do something that is too complicated for a single regex, or your regex is suboptimal.
EDIT: The typical cause of regexes taking too long is multiple quantifiers (?, , +) causing pathological backtracking. For example, if you try to match a string of N "A" characters followed by a "B" with the regex "^AAAAAA$", the complexity of the computation is (at least) O(N**5). Here's a more "real world" example:
"(.*)<html>(.*)<head>(.*)</head>(.*)<body>(.*)</body>(.*)</html>(.*)"
Now imagine what happens if you encounter a "web page" like this:
<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>
Notice that there is no closing </html>
tag. This will run for a long time before failing. (I'm not exactly sure what the complexity is ... but you can estimate it experimentally it you feel like it.)
In this case, a simple answer is to use simpler regexes to locate the 6 marker elements and then extract the stuff between then using substring()
.
Start your thread via an ExecutorService
and give it a timeout, like so:
ExecutorService pool = Executors.newFixedThreadPool(POOL_SIZE);
pool.execute(rt);
pool.awaitTermination(timeout, timeUnit);
awaitTermination() will wait until the task is finished (as well as all other tasks under this ExecutorService
), the thread is interrupted, or timeout occurs - which ever comes first.
Sounds like this fits your needs.
The Java Thread
class is not equipped to deal with this sort of interruption, and as such is not suitable for your requirements.
I would implement the functionality in a separate Process using the ProcessBuilder and use the Input and Output streams provided by the Process
class for communication. Forceful interruption is provided by the destroy method of of the Process
class.
I believe this is the correct, safest, implementation for the requirements you have. Unfortunately, Java doesn't make it easy to launch another Java process in a platform independent way so you'll have to have the java executable to your path and create a separate main
method to do this. This is harder than it should be.
I agree to check the regular expressions before they are used. If you need a safety net, you might use something like this...
http://gist.github.com/630969