私はjava.util.regex.Matcher
を使用するユーティリティメソッド(= static
)をたくさん持っています。渡された正規表現が多く再利用されているので、毎回コンパイルしないようにしています。Map
のキーがそのまま正規表現であり、値はList
でMatcher
オブジェクトです(各スレッドは自分自身にMatcher
インスタンス)。プールの問題:複数回借りたアイテム
次のコードスニペットは、同じMatcher
を2回返すことがあります。
import java.util.HashMap;
import java.util.HashSet;
import java.util.Map;
import java.util.Queue;
import java.util.Set;
import java.util.concurrent.ConcurrentLinkedQueue;
import java.util.regex.Matcher;
import java.util.regex.Pattern;
public class MyTest {
private static final Map<String, Queue<Matcher>> matchers = new HashMap<String, Queue<Matcher>>();
private static Set<Integer> duplicateHunter = new HashSet<Integer>();
private static Matcher getMatcher(String regexp, String value) {
Queue<Matcher> matcherQueue = matchers.get(regexp);
if (matcherQueue == null) {
synchronized (matchers) {
matcherQueue = matchers.get(regexp);
if (matcherQueue == null) {
// Create a new thread-safe Queue and a new Matcher
matcherQueue = new ConcurrentLinkedQueue<Matcher>();
matchers.put(regexp, matcherQueue);
} // Else: another thread already did what needed to be done
}
}
// Try to retrieve a Matcher
Matcher matcher = matcherQueue.poll();
if (matcher == null) {
// No matchers available, create one
// No lock needed, as it's not a drama to have a few more matchers in the queue
Pattern pattern = Pattern.compile(regexp);
matcher = pattern.matcher(value);
matcherQueue.offer(matcher);
} else {
// reset the matcher
matcher.reset(value);
}
// boolean notADuplicate = duplicateHunter.add(matcher.hashCode());
// if(!notADuplicate) {
// throw new RuntimeException("DUPLICATE!!!");
// }
return matcher;
}
private static void returnMatcher(String regex, Matcher matcher) {
Queue<Matcher> matcherQueue = matchers.get(regex);
//duplicateHunter.remove(matcher.hashCode());
matcherQueue.offer(matcher);
}
public static void main(String[] args) {
for (int i = 0; i < 2; i++) {
Thread thread = new Thread(new Runnable() {
public void run() {
for (int i = 0; i < 50000; i++) {
String regex = ".*";
Matcher matcher = null;
try {
matcher = getMatcher(regex, "toto" + i);
if (matcher.matches()) {
// matches
}
} finally {
if (matcher != null) {
returnMatcher(regex, matcher);
}
}
}
}
});
thread.start();
}
}
}
「java.lang.StringIndexOutOfBoundsException
:文字列インデックスが範囲外です。」が表示されます。 duplicateHunter
コードを有効にすると、実際にMatcher
が2回返されることがあります。
(static
ユーティリティメソッドが示されていない、main
方法があなたの問題を表示するためになされた)
なぜパターンの代わりにマッチャーをキャッシュしていますか?パターンが不変のスレッドセーフであるため、後者のアプローチがはるかに簡単になると思いました。 –
なぜ単にcommons-poolを使用しないのですか? – artbristol
@ジョン:別の質問の回答(http://stackoverflow.com/questions/7505160/high-performance-simple-java-regular-expressions)では、マッチャーを再利用するとパフォーマンスが「いくらか」向上すると言われています。そこにリンクされたマイクロベンチ(http://pastie.org/2570213)は、この小さなパフォーマンス向上を示しました。私はマイクロベンチがJavaで悪いことを知っていますが、私はまだ何とか確信していました。 – AndrewBourgeois