Java Regex线程安全吗?

更新时间:2024-05-03 下载TXT文档 下载Word文档

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

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

如果使用正则表达式,是否需要在此函数上放置synchronize? Java线程中的正则表达式安全吗?

是,来自Pattern类的Java API文档

Instances of this (Pattern) class are immutable and are safe for use by multiple concurrent threads. Instances of the Matcher class are not safe for such use.

如果您正在查看以性能为中心的代码,请尝试使用reset()方法重置Matcher实例,而不是创建新实例。这将重置Matcher实例的状态,使其可用于下一个正则表达式操作。实际上,正是Matcher实例中维护的状态才使它对于并发访问不安全。

  • 模式对象是线程安全的,但compile()方法可能不是。多年来,已经有两到三个错误导致在多线程环境中编译失败。我建议在同步块中进行编译。
  • 是的,Pattern类中出现了并发性错误,对于同步访问的建议,我们深表感谢。但是,Pattern类的原始开发人员打算使Pattern类作为线程安全,并且这是任何Java程序员都应该能够依赖的契约。坦率地说,Id宁愿拥有线程局部变量并接受对性能的最低要求,而不是依靠契约来依赖线程安全行为(除非Ive看过代码)。正如他们所说的"线程很容易,而正确的同步却很难"。
  • 请注意,"模式"的来源位于Oracle JDK发行版中(根据oracle.com/technetwork/java/faq-141681.html#A14:" Java 2 SDK,标准版本身包含一个名为src.zip的文件,包含java包中公共类的源代码"),因此您可以快速浏览一下。
  • @DavidTonhofer我认为我们最新的JDK可能具有正确的无错误代码,但是由于Javas中间.class文件可以在任何平台上通过任何兼容的VM进行解释,因此您不能确定这些修补程序存在于该运行时中。当然,大多数时候您都知道服务器正在运行哪个版本,但是检查每个版本都很繁琐。

Java中带有正则表达式的线程安全

SUMMARY:

The Java regular expression API has
been designed to allow a single
compiled pattern to be shared across
multiple match operations.

You can safely call
Pattern.matcher() on the same pattern from different threads and
safely use the matchers concurrently.
Pattern.matcher() is safe to construct matchers without
synchronization. Although the method
isn't synchronized, internal to the
Pattern class, a volatile variable
called compiled is always set after
constructing a pattern and read at the
start of the call to matcher().
This forces any thread referring to
the Pattern to correctly"see" the
contents of that object.

On the other hand, you shouldn't share
a Matcher between different threads.
Or at least, if you ever did, you
should use explicit synchronization.

[短码网_DuanMa.NET]

  • @akf,顺便说一句,您应该注意,多数民众赞成在一个讨论站点(非常类似于此站点)。我认为您在这里找到的任何信息都不会比在这里找到的信息更好或更糟(即,不是詹姆斯·高斯林的《一个真实的词》)。

尽管您需要记住线程安全性也必须考虑周围的代码,但是您似乎很幸运。匹配器是使用Pattern的matcher工厂方法创建的,并且缺少公共构造函数,这是一个积极的信号。同样,您可以使用compile static方法创建包含模式。

简而言之,如果您执行类似示例的操作:

Pattern p = Pattern.compile("a*b");
Matcher m = p.matcher("aaaaab");
boolean b = m.matches();

你应该做得不错。

为了清楚起见,对代码示例进行了后续处理:请注意,此示例强烈暗示由此创建的Matcher在Pattern和测试中是线程局部的。即,您不应将由此创建的Matcher暴露给任何其他线程。

坦白说,这就是任何线程安全问题的风险。现实情况是,如果您努力尝试,任何代码都可能被设置为线程不安全的。幸运的是,有很多很棒的书,教给我们很多破坏代码的方式。如果我们避免这些错误,那么将大大降低我们自己出现线程问题的可能性。

  • @Jason S:即使内部代码不是线程安全的,线程局部性也是实现线程安全的一种非常简单的方法。如果一次只能访问一种方法,则可以从外部强制执行线程安全。
  • 好的,所以您只是说在使用时从字符串重新创建模式比将其高效存储要好,这有处理并发问题的风险?生病的你。我对关于工厂方法和公共构造函数的句子感到困惑,这似乎是一个无聊的话题。
  • @Jason S,不,工厂方法和缺少构造函数是可以减少与其他线程耦合的威胁的一些方法。如果获取与我的模式匹配的Matcher的唯一方法是通过p.matcher(),则没有其他人可以对我的Matcher产生副作用。但是,我仍然会给自己造成麻烦:如果我有一个返回该Matcher的公共方法,则另一个线程可能会遇到该问题并产生副作用。简而言之,并发很难(使用任何语言)。

快速浏览Matcher.java的代码将显示一堆成员变量,包括要匹配的文本,组的数组,用于维护位置的一些索引以及用于其他状态的一些boolean。所有这些都指向一个有状态的Matcher,如果被多个Threads访问,该状态将不会表现良好。 JavaDoc也是如此:

Instances of this class are not safe for use by multiple concurrent
threads.

正如@Bob Cross指出的那样,这只是一个问题,如果您竭尽所能允许在单独的Thread中使用Matcher。如果需要执行此操作,并且认为同步将成为代码问题,那么您可以选择使用ThreadLocal存储对象在每个工作线程中维护Matcher

综上所述,您可以重用(保留静态变量)已编译的Pattern,并告诉它们在需要验证某些字符串的正则表达式模式时为您提供新的Matchers。

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/(接近尾声)(万一它不适合那些需要通过电子邮件验证的人,因为它在这里发布)

  • 感谢您发布答案!请务必仔细阅读有关自我促销的常见问题解答。有人可能会看到此答案和链接到博客的文章,并认为您只是发布了博客文章,因此可以从此处链接到它。
  • 为什么要困扰static {}?您可以内联该变量初始化,并同时创建Pattern final
  • 我第二个观点是TWiStErRob:private static final Pattern emailPattern = Pattern.compile(EMAIL_PATTERN);更好。

以上就是短码网小编为大家整理的《Java Regex线程安全吗?》相关内容,希望大家喜欢。

本文来自互联网用户投稿,该文观点仅代表作者本人,不代表本站立场。本站仅提供信息存储空间服务,不拥有所有权,不承担相关法律责任。

如若内容造成侵权/违法违规/事实不符,请将联系本站反馈,一经查实,立即处理!

Java Regex线程安全吗?》文档下载仅供参考学习,下载后请在24小时内删除。

转载注明出处:https://www.duanma.net/article/3aaf02c6608.html

回到顶部