Java 在REST中处理相同的并发请求
大家好! 我有一个休息,基于球衣的申请。此应用程序(由于其客户端的性质)在大致相同的时间(相隔约2-5秒)接收相同的http请求(其中3-6个)。 每个请求大约需要10秒来处理,并带回大量数据(点击数据库、进行数据按摩等)。 在理想情况下,我希望避免多次处理同一请求,并考虑编写某种请求过滤器,只允许唯一请求通过,而其他请求将被阻止,直到允许的请求返回。 被阻止的请求还将向调用者返回相同的数据(通过在服务器上查找缓存的响应) 这种方法的优点/缺点是什么?Java 在REST中处理相同的并发请求,java,rest,concurrency,jersey,request,Java,Rest,Concurrency,Jersey,Request,大家好! 我有一个休息,基于球衣的申请。此应用程序(由于其客户端的性质)在大致相同的时间(相隔约2-5秒)接收相同的http请求(其中3-6个)。 每个请求大约需要10秒来处理,并带回大量数据(点击数据库、进行数据按摩等)。 在理想情况下,我希望避免多次处理同一请求,并考虑编写某种请求过滤器,只允许唯一请求通过,而其他请求将被阻止,直到允许的请求返回。 被阻止的请求还将向调用者返回相同的数据(通过在服务器上查找缓存的响应) 这种方法的优点/缺点是什么? 除了更改客户端逻辑之外,还有其他更好的解决
除了更改客户端逻辑之外,还有其他更好的解决方案吗;) 您可以为每个“键”创建一个唯一的对象来锁定。其中键是一些请求参数,在本例中是一个
字符串
。这样,您只需保留请求(因为同步),一旦计算完成,两个客户端几乎同时返回结果。这样,客户机就不必发出多个请求,而不是首先发出请求的客户机必须等待第一个客户机启动缓存
import java.util.HashMap;
import java.util.concurrent.ConcurrentHashMap;
public class Hold {
private ConcurrentHashMap<String, String> holds =
new ConcurrentHashMap<>(new HashMap<String, String>());
// compose a "hash" for lack of better word, could append a timeout as well
public String hashString (String string) {
return string + "wackystuff";
}
public String doLongComputation () {
// do crazy computation here
return new String();
}
public synchronized String getResults (String key) {
// give us a unique object for this key to lock on
holds.putIfAbsent(key, hashString(key));
// lock on that key
synchronized (holds.get(key)) {
// we have a non lock value so return it
if (!holds.get(key).equals(hashString(key))) {
// could do some timeout here
return holds.get(key);
}
// the cache is empty so do the long computation
holds.put(key, doLongComputation());
}
return holds.get(key);
}
}
import java.util.HashMap;
导入java.util.concurrent.ConcurrentHashMap;
公开课举行{
私有ConcurrentHashMap保持=
新的ConcurrentHashMap(新的HashMap());
//为缺少更好的单词而编写一个“哈希”,也可以附加一个超时
公共字符串哈希字符串(字符串字符串){
返回字符串+“wackystuff”;
}
公共字符串计算(){
//在这里做疯狂的计算
返回新字符串();
}
公共同步字符串getResults(字符串键){
//给我们一个唯一的对象让这把钥匙锁定
holds.putIfAbsent(key,hashString(key));
//锁上那把钥匙
已同步(保持。获取(键)){
//我们有一个非锁定值,所以返回它
如果(!holds.get(key).equals(hashString(key))){
//我可以在这里暂停一下吗
返回holds.get(键);
}
//缓存是空的,因此进行长时间计算
holds.put(key,dolongcompulation());
}
返回holds.get(键);
}
}
这只是一种狡猾的方法,这本书《实践中的Java并发》(Java Concurrency in Practice)中有更健壮的方法,它在第5.19节中,代码示例可以找到
以下是这种方法的优缺点:
- 赞成:客户只需提出一个请求
- 赞成:你不是在重新计算结果
- 赞成:没有单个客户端的等待时间在串行情况下增加
- 缺点:在计算过程中,您正在保留一个VM线程,这是每个客户端的。鉴于您拥有查看客户端,这不应该是一个问题
- 缺点:考虑一个好的时间表来清除缓存可能很棘手
这种方法是在使用REST服务数年后创建的,在我们的解决方案中效果非常好 谢谢,但我的问题是关于在服务器端这样做的利弊。你认为这种方法有什么问题?我已经更新了我的答案,展示了一些优点和缺点。谢谢@Victory。这是有道理的。对于这个问题,你能想到其他的解决办法吗?我能想到2个(我都不喜欢):1。在客户端和服务器2之间添加代理。在客户端添加筛选器。这两种方法都不能消除服务器端并发请求的风险。我认为代理将更加棘手,因为它需要相同的逻辑,而不需要相同的作用域。过滤器是一个想法,但是你会要求客户“表现良好”,这不是一个好的假设。这是一个良好的API设计IMHO的反模式。