Java Regex Thread是安全的吗?

时间:2009-09-01 01:04:19

标签: java regex multithreading

我有一个使用Pattern#compileMatcher的函数来搜索模式的字符串列表。

此函数用于多个线程。创建线程时,每个线程都将传递给Pattern#compile的唯一模式。线程和模式的数量是动态的,这意味着我可以在配置期间添加更多Pattern和线程。

如果使用正则表达式,我是否需要在此函数上加synchronize? java线程中的正则表达式是否安全?

5 个答案:

答案 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/(接近结尾)(如果它不符合电子邮件验证的需要,因为它在此处发布)