gpt4 book ai didi

java - 池化问题 : Item borrowed more than once

转载 作者:行者123 更新时间:2023-11-29 08:09:36 25 4
gpt4 key购买 nike

我有一个我经常调用的实用方法(=一个static),它使用一个java.util.regex.Matcher .由于传递的正则表达式被大量重复使用,我尽量不每次都编译它,所以我将它保存在 Map 中。其中键是正则表达式,值是 ListMatcher对象(这样每个线程都有自己的 Matcher 实例)。

下面的代码片段是如何设法返回相同的 Matcher 的?两次……有时?

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确实有时会返回两次。

(未显示 static 实用方法,main 方法是为了向您展示问题)

最佳答案

当正则表达式没有匹配器时,你创建一个新的匹配器,但你也立即将它添加到队列中:

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); // Don't add it to the queue here!
}

因此,当您使用它时,它会在队列中,并且另一个线程可以在您完成之前轻松获得它。

顺便说一句,我不知道我是否同意你池化匹配器的想法。就 CPU 周期而言,它们的创建成本并不高。您可能想要分析它以查看它是否值得。不过,预编译 Pattern 是个好主意。

关于java - 池化问题 : Item borrowed more than once,我们在Stack Overflow上找到一个类似的问题: https://stackoverflow.com/questions/8934051/

25 4 0
Copyright 2021 - 2024 cfsdn All Rights Reserved 蜀ICP备2022000587号
广告合作:1813099741@qq.com 6ren.com