我有一个使用Pattern#compile
和Matcher
的函数来搜索模式的字符串列表。
此函数用于多个线程。创建线程时,每个线程都将传递给Pattern#compile
的唯一模式。线程和模式的数量是动态的,这意味着我可以在配置期间添加更多Pattern
和线程。
如果使用正则表达式,我是否需要在此函数上加synchronize
? java线程中的正则表达式是否安全?
答案 0 :(得分:119)
是,来自Pattern class
的Java API文档此(Pattern)类的实例是不可变的,并且可以安全地供多个并发线程使用。 Matcher类的实例不适合此类使用。
如果您正在查看以性能为中心的代码,请尝试使用reset()方法重置Matcher实例,而不是创建新实例。这将重置Matcher实例的状态,使其可用于下一个正则表达式操作。实际上,正是在Matcher实例中维护的状态导致它对并发访问不安全。
答案 1 :(得分:8)
Thread-safety with regular expressions in Java
内容:
Java正则表达式API具有 被设计为允许单个 编译模式以进行共享 多重匹配操作。
你可以安全地打电话 来自不同线程的相同模式的 Pattern.matcher() 安全地同时使用匹配器。 Pattern.matcher()可以安全地构建匹配器 同步。虽然方法 是不同步的,内部的 模式类,一个volatile变量 调用编译后始终设置 构建模式并阅读 开始调用 matcher()。 这迫使任何线程引用 模式正确地“看”了 该对象的内容。
另一方面,你不应该分享 不同线程之间的匹配器。 或者至少,如果你曾经做过,那么你 应该使用显式同步。
答案 2 :(得分:3)
虽然您需要记住线程安全性也必须考虑周围的代码,但您似乎很幸运。使用Pattern的Matchers工厂方法创建matcher并且缺少公共构造函数这一事实是一个积极的信号。同样,您使用compile静态方法创建包含Pattern。
因此,简而言之,如果您执行类似示例的操作:
Pattern p = Pattern.compile("a*b");
Matcher m = p.matcher("aaaaab");
boolean b = m.matches();
你应该做得很好。
为了清晰起见,对代码示例进行了跟进:请注意,此示例强烈暗示这样创建的Matcher是使用Pattern和测试进行线程本地化的。即,您不应该将这样创建的Matcher暴露给任何其他线程。
坦率地说,这是任何线程安全问题的风险。实际情况是,如果你足够努力,任何代码都可以成为线程不安全的。幸运的是,有wonderful books告诉我们一系列可能破坏我们代码的方法。如果我们远离这些错误,我们会大大降低我们自己处理线程问题的可能性。答案 3 :(得分:2)
快速查看Matcher.java
的代码,显示了一堆成员变量,包括匹配的文本,组的数组,维护位置的一些索引以及其他的boolean
个州。这一切都指向有状态的Matcher
,如果由多个Threads
访问,则表现不佳。 JavaDoc:
此类的实例不适合多个并发使用 线程。
如果正如@Bob Cross指出的那样,您只是在允许在单独的Matcher
中使用Thread
的情况下,这只是一个问题。如果您需要执行此操作,并且您认为同步将成为您的代码的问题,那么您可以选择使用ThreadLocal
存储对象来维护每个工作线程Matcher
。
答案 4 :(得分:1)
总而言之,您可以重用(保留在静态变量中)已编译的模式,并告诉他们在需要时为您提供新的匹配器,以针对某些字符串验证这些正则表达式模式
import java.util.regex.Matcher;
import java.util.regex.Pattern;
/**
* Validation helpers
*/
public final class Validators {
private static final String EMAIL_PATTERN = "^[_A-Za-z0-9-]+(\\.[_A-Za-z0-9-]+)*@[A-Za-z0-9-]+(\\.[A-Za-z0-9-]+)*(\\.[A-Za-z]{2,})$";
private static Pattern email_pattern;
static {
email_pattern = Pattern.compile(EMAIL_PATTERN);
}
/**
* Check if e-mail is valid
*/
public static boolean isValidEmail(String email) {
Matcher matcher = email_pattern.matcher(email);
return matcher.matches();
}
}
请参阅上面用于验证电子邮件的RegEx模式的http://zoomicon.wordpress.com/2012/06/01/validating-e-mails-using-regular-expressions-in-java/(接近结尾)(如果它不符合电子邮件验证的需要,因为它在此处发布)