Java Regex 스레드는 안전합니까? 가지고 Pattern#compile와이 Matcher패턴에 대한

내가 사용하는 기능을 가지고 Pattern#compile와이 Matcher패턴에 대한 문자열 목록을 검색 할 수 있습니다.

이 함수는 여러 스레드에서 사용됩니다. 각 스레드에는 고유 한 패턴이Pattern#compile 에는 스레드가 생성 될 때 . 스레드와 패턴의 수는 동적이므로 Pattern구성 중에 더 많은 스레드와 스레드를 추가 할 수 있습니다 .

synchronize정규식을 사용하는 경우이 함수에 추가해야 합니까? Java 스레드의 정규식은 안전합니까?



답변

, Pattern 클래스에 대한 Java API 문서에서

이 (Pattern) 클래스의 인스턴스는 변경할 수 없으며 여러 동시 스레드에서 사용하기에 안전합니다. Matcher 클래스의 인스턴스는 이러한 사용에 안전하지 않습니다.

성능 중심 코드를보고있는 경우 새 인스턴스를 만드는 대신 reset () 메서드를 사용하여 Matcher 인스턴스를 재설정하십시오. 이렇게하면 Matcher 인스턴스의 상태가 재설정되어 다음 정규식 작업에 사용할 수 있습니다. 실제로 동시 액세스에 대해 안전하지 않은 것은 Matcher 인스턴스에서 유지되는 상태입니다.


답변

Java에서 정규식을 사용한 스레드 안전성

요약:

Java 정규식 API는 여러 일치 작업에서 단일 컴파일 된 패턴을 공유 할 수 있도록 설계되었습니다.

다른 스레드에서 동일한 패턴에 대해 Pattern.matcher () 를 안전하게 호출
하고 동시에 매처를 안전하게 사용할 수 있습니다.
Pattern.matcher () 는 동기화없이 매처를 생성하는 것이 안전합니다. 메서드가 동기화되지는 않지만 Pattern 클래스 내부에 있지만, 패턴을 생성 한 후에는 항상 compile이라는 휘발성 변수가 설정되고 matcher () 호출이 시작될 때 읽습니다 .
이렇게하면 Pattern을 참조하는 모든 스레드가 해당 개체의 내용을 올바르게 “볼”수 있습니다.

반면에 서로 다른 스레드간에 Matcher를 공유해서는 안됩니다. 또는 적어도 그렇게했다면 명시 적 동기화를 사용해야합니다.


답변

스레드 안전성은 주변 코드도 고려해야한다는 것을 기억해야하지만 운이 좋은 것 같습니다. 사실 매처 (Matchers)이 패턴의 사용하여 만들어집니다 정규의 팩토리 메소드와 public 생성자 부족은 긍정적이다. 마찬가지로 컴파일 정적 메서드를 사용하여 포함하는 패턴 을 만듭니다. .

간단히 말해 예와 같은 작업을 수행하면 다음과 같습니다.

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

당신은 꽤 잘하고 있어야합니다.

명확성을 위해 코드 예제에 대한 후속 조치 :이 예제는 이렇게 생성 된 Matcher가 Pattern 및 테스트와 함께 스레드 로컬임을 강력하게 암시합니다. 즉, 이렇게 생성 된 Matcher를 다른 스레드에 노출해서는 안됩니다.

솔직히 이것은 스레드 안전성 질문의 위험입니다. 현실은 충분히 노력하면 모든 코드가 스레드에 안전하지 않게 될 수 있다는 것입니다. 다행히도 우리가 코드를 망칠 수있는 모든 방법을 가르쳐주는 멋진 들이 있습니다. 이러한 실수를 피하면 스레딩 문제가 발생할 가능성이 크게 줄어 듭니다.


답변

에 대한 코드를 간략히 살펴보면 Matcher.java일치하는 텍스트, 그룹 배열, 위치 유지 관리를위한 몇 가지 인덱스, boolean다른 상태를위한 몇 가지를 포함하는 여러 멤버 변수가 표시 됩니다. 이 모든 Matcher것은 다중에서 액세스 할 경우 제대로 작동하지 않는 상태 저장 을 가리 킵니다 Threads. JavaDoc도 마찬가지입니다 .

이 클래스의 인스턴스는 여러 동시 스레드에서 사용하기에 안전하지 않습니다.

@Bob Cross가 지적했듯이 Matcher별도 Thread의 s 에서 사용을 허용하는 경우에만 문제가됩니다 . 이 작업을 수행해야하고 코드에서 동기화가 문제가 될 것이라고 생각하는 경우에는 ThreadLocal저장소 개체를 사용하여 Matcher작업 스레드 당 유지 관리 할 수 있습니다.


답변

요약하면, 컴파일 된 패턴을 재사용 (정적 변수에 유지)하고 일부 문자열에 대해 해당 정규식 패턴의 유효성을 검사해야 할 때 새 매처를 제공하도록 지시 할 수 있습니다.

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/ (끝 근처)를 참조하십시오. 여기에 게시 된대로 이메일 검증을위한 요구 사항에 맞지 않는 경우)


답변