Java 池问题:多次借用的项目

Java 池问题:多次借用的项目,java,multithreading,Java,Multithreading,我有一个我经常调用的实用方法(staticone),它使用java.util.regex.Matcher。由于传递的regex被大量重用,我尽量不每次编译它,所以我将它保存在映射中,其中键是regex,值是匹配器对象的列表(这样每个线程都有自己的匹配器实例) 下面的代码段如何两次返回相同的Matcher。。。有时 import java.util.HashMap; import java.util.HashSet; import java.util.Map; import java.util.Q

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

下面的代码段如何两次返回相同的
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();
        }

    }
}
import java.util.HashMap;
导入java.util.HashSet;
导入java.util.Map;
导入java.util.Queue;
导入java.util.Set;
导入java.util.concurrent.ConcurrentLinkedQueue;
导入java.util.regex.Matcher;
导入java.util.regex.Pattern;
公共类MyTest{
私有静态最终映射匹配器=新HashMap();
私有静态集duplicateHunter=newHashSet();
私有静态匹配器getMatcher(字符串regexp,字符串值){
Queue matcherQueue=matchers.get(regexp);
if(matcherQueue==null){
同步(匹配器){
matcherQueue=matchers.get(regexp);
if(matcherQueue==null){
//创建一个新的线程安全队列和一个新的匹配器
matcherQueue=新的ConcurrentLinkedQueue();
put(regexp,matcherQueue);
}//否则:另一个线程已经执行了需要执行的操作
}
}
//尝试检索匹配器
Matcher Matcher=matcherQueue.poll();
if(matcher==null){
//没有可用的匹配器,请创建一个
//不需要锁,因为队列中再多几个匹配者不是闹剧
Pattern=Pattern.compile(regexp);
匹配器=模式匹配器(值);
matcherQueue.offer(matcher);
}否则{
//重置匹配器
匹配器重置(值);
}
//boolean notadicate=duplicateHunter.add(matcher.hashCode());
//如果(!不重复){
//抛出新的RuntimeException(“复制!!!”);
//        }
返回匹配器;
}
私有静态void returnMatcher(字符串正则表达式,Matcher Matcher){
Queue matcherQueue=matchers.get(regex);
//duplicateHunter.remove(matcher.hashCode());
matcherQueue.offer(matcher);
}
公共静态void main(字符串[]args){
对于(int i=0;i<2;i++){
Thread Thread=新线程(new Runnable(){
公开募捐{
对于(int i=0;i<50000;i++){
字符串regex=“*”;
Matcher-Matcher=null;
试一试{
matcher=getMatcher(regex,“toto”+i);
if(matcher.matches()){
//火柴
}
}最后{
如果(匹配器!=null){
returnMatcher(regex,matcher);
}
}
}
}
});
thread.start();
}
}
}
您将得到一个“
java.lang.StringIndexOutOfBoundsException
:字符串索引超出范围”。启用
duplicateHunter
代码,您将看到
Matcher
有时确实会返回两次


(未显示
static
实用程序方法,使用
main
方法向您显示问题)

如果没有regexp的匹配器,您可以创建一个新的匹配器,但也可以立即将其添加到队列中:

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周期而言,创建它们并不十分昂贵。你可能想分析一下,看看它是否值得。但是,预编译
模式是一个好主意。

当regexp没有匹配器时,您可以创建一个新的匹配器,但也可以立即将其添加到队列中:

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周期而言,创建它们并不十分昂贵。你可能想分析一下,看看它是否值得。但是,预编译
模式是一个好主意。

当您创建一个新的匹配器时,您在返回它之前将它提供给队列,以便下一个线程立即获得它

matcher = pattern.matcher(value);  
matcherQueue.offer(matcher);        // <-- this line should be taken taken out and shot

...

return matcher;
matcher=pattern.matcher(值);

matcherQueue.offer(matcher);// 当您创建一个新的匹配器时,您在返回它之前将它提供给队列,以便下一个线程立即获得它

matcher = pattern.matcher(value);  
matcherQueue.offer(matcher);        // <-- this line should be taken taken out and shot

...

return matcher;
matcher=pattern.matcher(值);

matcherQueue.offer(matcher);//为什么缓存匹配器而不是模式?我原以为后一种方法会简单得多,因为模式是不可变的线程安全的。为什么不使用commons pool呢?@Jon:另一个问题的回答()告诉我,重用Matchers可以“提高”性能。连接在那里的微型工作台()显示了这一点性能提升。我知道微本在Java中是不好的,但我还是有点信服。@AndrewBourgeois:你更喜欢哪种:复杂的、有缺陷的代码,在微基准测试中可能会有一些性能提升,但没有证据表明这种提升在你的应用程序中是显著的,或者简单的
ConcurrentHashMap
,很难出错,而且几乎肯定会足够好吗?这是一个微观优化:在证明需要之前不要这样做。@JonSkeet:我会在真正的应用程序中测试这两个。该方法是一个程序的一部分,该程序全年使用100%的CPU核