回答:
はい、Patternクラスの Java APIドキュメントから
この(Pattern)クラスのインスタンスは不変であり、複数の同時スレッドで安全に使用できます。Matcherクラスのインスタンスは、そのような使用には安全ではありません。
パフォーマンス中心のコードを見ている場合は、新しいインスタンスを作成する代わりに、reset()メソッドを使用してMatcherインスタンスをリセットしてみてください。これにより、Matcherインスタンスの状態がリセットされ、次の正規表現操作で使用できるようになります。実際、Matcherインスタンスで維持される状態は、同時アクセスに対して安全ではないことを担っています。
概要:
Java正規表現APIは、単一のコンパイル済みパターンを複数の一致操作で共有できるように設計されています。
異なるスレッドから同じパターンでPattern.matcher()を安全に呼び出すことができ 、マッチャーを同時に安全に使用できます。 Pattern.matcher()は、同期せずにマッチャーを構築しても安全です。このメソッドは、Patternクラスの内部で同期化されていませんが、パターンを作成した後は常に、compiledと呼ばれる揮発性変数が設定され、matcher()の呼び出しの開始時に読み取られます。 これにより、パターンを参照するすべてのスレッドは、そのオブジェクトの内容を正しく「見る」ことができます。
一方、異なるスレッド間でマッチャーを共有しないでください。または、少なくとも、使用したことがある場合は、明示的な同期を使用する必要があります。
スレッドセーフは周囲のコードも考慮する必要があることを覚えておく必要がありますが、幸運なようです。事実の照合プログラムは、パターンの使用して作成されたマッチャーファクトリメソッドを、パブリックコンストラクタを持たないが正の符号です。同様に、静的なコンパイル方法を使用して、包含パターンを作成します。
つまり、簡単に言うと、例のようなことをすると:
Pattern p = Pattern.compile("a*b");
Matcher m = p.matcher("aaaaab");
boolean b = m.matches();
あなたはかなりうまくいっているはずです。
わかりやすくするためにコード例のフォローアップ:この例は、このように作成されたマッチャーがパターンとテストでスレッドローカルであることを強く示唆していることに注意してください。つまり、作成したマッチャーを他のスレッドに公開しないでください。
率直に言って、それはスレッドセーフの質問のリスクです。実際には、十分な努力をすると、すべてのコードがスレッドセーフにならない可能性があります。幸いなことに、コードを台無しにしてしまう可能性のあるたくさんの方法を教えてくれる素晴らしい 本があります。これらのミスを避ければ、スレッド化の問題が発生する可能性が大幅に減少します。
のコードをざっと見てみると、Matcher.java
一致するテキスト、グループの配列、位置を維持するためのいくつかのインデックスboolean
、その他の状態のためのいくつかのs など、メンバー変数の束が示されています。これはすべてMatcher
、複数からアクセスされた場合に適切に動作しないステートフルを指しますThreads
。JavaDocも同様です。
このクラスのインスタンスは、複数の同時スレッドによる使用には安全ではありません。
これは、@ Bob Crossが指摘しているようにMatcher
、別Thread
のでの使用を許可するために邪魔になった場合にのみ問題になります。これを行う必要があり、コードの同期が問題になると思われる場合は、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();
}
}
参照http://zoomicon.wordpress.com/2012/06/01/validating-e-mails-using-regular-expressions-in-java/を(電子メールを検証するために上記で使用正規表現パターンについて(端部近傍)ここに投稿されているため、電子メール検証のニーズに適合しない場合)
static {}
?その変数の初期化をインライン化して、Pattern
final
同様に作成できます。
private static final Pattern emailPattern = Pattern.compile(EMAIL_PATTERN);
より優れています。
compile()
メソッドはそうでない場合があります。マルチスレッド環境でコンパイルが失敗する原因となったバグは、長年にわたって2〜3個ありました。コンパイルを同期ブロックで行うことをお勧めします。