我将一个无状态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线程?
对于我如何做得更好的任何想法都非常感激。
答案 0 :(得分:0)
首先,如果我能重申你的理由是为了清楚。对于任何给定的密钥,所有请求必须在单个线程中处理;但是,对其他密钥的请求可以在处理第一个密钥的请求的同时进行处理。
这让我感觉非常适合ExecutorService。我会使您的地图成为<String, ExecutorService>
地图,其中键是您的队列密钥,值是单线程执行程序(可以通过Executors.newSingleThreadExecutor()获得)。
根据密钥,您将从地图中获得ExecutorService
,然后提交您要处理的Callable。因为此密钥的Executor
是单线程的,所以可以确保它将等到该密钥的先前请求在处理之前已经处理完毕。然后,对get的调用将被阻止,直到完成此请求的处理为止。