Java Regex Thread Safe? - PullRequest
       36

Java Regex Thread Safe?

96 голосов
/ 01 сентября 2009

У меня есть функция, которая использует Pattern#compile и Matcher для поиска в списке строк для шаблона.

Эта функция используется в нескольких потоках. Каждый поток будет иметь уникальный шаблон, переданный в Pattern#compile при создании потока. Количество потоков и шаблонов является динамическим, что означает, что я могу добавить больше Pattern s и потоков во время конфигурации.

Нужно ли ставить synchronize для этой функции, если она использует регулярные выражения? Является ли регулярное выражение в потоке Java безопасным?

Ответы [ 5 ]

120 голосов
/ 01 сентября 2009

Да , из документации API Java для класса Pattern

Экземпляры этого (Pattern) класса являются неизменяемыми и безопасными для использования несколькими параллельными потоками. Экземпляры класса Matcher не безопасны для такого использования.

Если вы смотрите на код, ориентированный на производительность, попытайтесь сбросить экземпляр Matcher с помощью метода reset () вместо создания новых экземпляров. Это сбрасывает состояние экземпляра Matcher, делая его пригодным для следующей операции регулярного выражения. Фактически, именно состояние, поддерживаемое в экземпляре Matcher, отвечает за его безопасность для одновременного доступа.

9 голосов
/ 01 сентября 2009

Потокобезопасность с регулярными выражениями в Java

РЕЗЮМЕ:

API регулярных выражений Java имеет был разработан, чтобы позволить один скомпилированный шаблон для совместного использования несколько операций сопоставления.

Можете смело звонить Pattern.matcher () на одном и том же шаблоне из разных потоков и безопасно использовать совпадения одновременно. Pattern.matcher () безопасно создавать сопоставители без синхронизации. Хотя метод не синхронизировано, внутреннее Класс Pattern, переменная переменная вызываемый скомпилированный всегда устанавливается после построить шаблон и читать на начало вызова на matcher (). Это заставляет любой поток, ссылающийся на Шаблон, чтобы правильно «увидеть» содержимое этого объекта.

С другой стороны, вы не должны делиться Сопоставитель между разными потоками. Или, по крайней мере, если вы когда-либо делали, вы следует использовать явную синхронизацию.

3 голосов
/ 01 сентября 2009

Хотя вы должны помнить, что безопасность потоков должна учитывать и окружающий код, вам, похоже, повезло. Тот факт, что Matchers созданы с использованием фабричного метода Pattern * matcher и отсутствие открытых конструкторов, является положительным знаком. Аналогично, вы используете статический метод compile для создания охватывающего Pattern .

Итак, вкратце, если вы делаете что-то вроде примера:

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

у тебя должно быть все хорошо.

Для ясности следуйте примеру кода: обратите внимание, что этот пример строго подразумевает, что созданный таким образом Matcher является локальным для потока с шаблоном и тестом. То есть вы не должны подвергать Matcher, созданный таким образом, никаким другим потокам.

Честно говоря, это риск любого вопроса безопасности потока. Реальность такова, что любой код может стать небезопасным, если вы попытаетесь достаточно усердно. К счастью, есть замечательных книг , которые учат нас целому ряду способов, которыми мы могли бы испортить наш код. Если мы будем держаться подальше от этих ошибок, мы значительно снизим вероятность возникновения проблем с потоками.

2 голосов
/ 01 сентября 2009

Беглый взгляд на код для Matcher.java показывает набор переменных-членов, включая сопоставляемый текст, массивы для групп, несколько индексов для определения местоположения и несколько boolean s для другого состояния. Все это указывает на состояние Matcher, которое не будет вести себя хорошо, если к нему будет обращаться несколько Threads. Так же, как и JavaDoc :

Экземпляры этого класса не безопасны для использования несколькими одновременными потоки.

Это проблема, только если, как указывает @Bob Cross, вы стараетесь изо всех сил разрешить использование Matcher в отдельных Thread s. Если вам нужно сделать это, и вы считаете, что синхронизация будет проблемой для вашего кода, у вас есть возможность использовать ThreadLocal объект хранилища для поддержки Matcher для каждого рабочего потока.

1 голос
/ 01 июня 2012

Подводя итог, вы можете повторно использовать (сохранять в статических переменных) скомпилированные Шаблоны и сказать им, чтобы они давали вам новые 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();
  }

}

см. http://zoomicon.wordpress.com/2012/06/01/validating-e-mails-using-regular-expressions-in-java/ (ближе к концу) относительно шаблона RegEx, использованного выше для проверки электронной почты (в случае, если он не соответствует потребностям в проверке электронной почты, так как она размещена здесь)

Добро пожаловать на сайт PullRequest, где вы можете задавать вопросы и получать ответы от других членов сообщества.
...