Java tomcat如何只排队某些http线程?

时间:2011-10-31 09:41:55

标签: java concurrency concurrenthashmap

我将一个无状态Java应用程序部署到tomcat Web服务器。由于数据的性质,在任何给定时间,所有http线程都必须处理不同的密钥(换句话说:所有线程必须处理不同的密钥)。

因此,如果请求的密钥正在进行中(在此之前通过http帖子),我编写了一个对http post排队的模块。一旦使用相同密钥的上一个http帖子完成其过程,我将继续处理当前的http帖子。

我已经使用concurrenthashmap编写了一个简单的while循环来测试是否存在任何具有相同密钥的先前请求。性能低于标准,并且存在意外行为。这是代码段:

//This part of code is place inside the servlet 
private static ConcurrentHashMap<String, String> transQueue = new ConcurrentHashMap<String, String>();
private void inQueuePoll(String queueKey) {
   while(transQueue.containsKey(queueKey)){     
      synchronized(this){
         try{
            Thread.sleep(50); // i know this is bad, any idea to improve this?
            logger.trace("Wait for Que Key: "+queueKey + " );

            }catch (InterruptedException e) {
                e.printStackTrace();
            }
        }
    }
    transQueue.put(queueKey, "");
}

在每个http帖子的最后,在finally块中,我输入:transQueue.remove(queueKey)以确保我已将其从concurrenthashmap中删除。但是,在我最糟糕的噩梦中,从服务器日志中,我注意到在删除queueKey之前,另一个http帖子线程,设法退出上面的while循环并继续处理。

上面的代码是否有任何错误来“排队”http线程?

对于我如何做得更好的任何想法都非常感激。

1 个答案:

答案 0 :(得分:0)

首先,如果我能重申你的理由是为了清楚。对于任何给定的密钥,所有请求必须在单个线程中处理;但是,对其他密钥的请求可以在处理第一个密钥的请求的同时进行处理。

这让我感觉非常适合ExecutorService。我会使您的地图成为<String, ExecutorService>地图,其中键是您的队列密钥,值是单线程执行程序(可以通过Executors.newSingleThreadExecutor()获得)。

根据密钥,您将从地图中获得ExecutorService,然后提交您要处理的Callable。因为此密钥的Executor是单线程的,所以可以确保它将等到该密钥的先前请求在处理之前已经处理完毕。然后,对get的调用将被阻止,直到完成此请求的处理为止。