提问人:Cesar Lopes 提问时间:9/16/2023 最后编辑:Cesar Lopes 更新时间:9/16/2023 访问量:61
在 Spring Web 方法中限制并发线程
Limit concurrent Threads in Spring Web Method
问:
我有一个Spring Web MVC应用程序,它在SOAP中有一个名为calculateWebMethod的Web方法。
由于并发请求的数量,服务器过载,我的团队决定将 Web 方法调用为公共静态同步方法,以使请求在单个 Thread 中运行,并且重载进入队列。CalculateTask
所以基本上我们有这个场景:
public class CalculateBean {
public static synchronized long CalculateTask(params...) {
long result = null;
... code to calculate
return result;
}
}
@WebMethod(operationName="calculateWebMethod", action="calculateWebMethod")
public calculateWebMethodResponse calculateWebMethod(
@WebParam(name="param1") String param1,
@WebParam(name="param2") String param2,
...
) {
...
long webMethodResult = CalculateBean.CalculateTask(...params);
return webMethodResult;
}
问题是队列太长,无法在可接受的时间内处理所有请求,但将所有内容都留在多个线程中会使服务器过载,是否可以限制执行 10 个或 n 个并发的线程数设置此执行时间限制并使重载进入队列?CalculateTask
答:
当发出多个请求时,这将在并行线程中执行,首先您必须删除表单静态方法。
现在的问题是,由于服务器中的资源有限,无法处理大量的并发请求。
假设只允许 10 个并发请求,当请求出现时,如果存在 10 个正在进行的请求,则应定义预期的行为(天气它返回错误或请求排队。 如果是第二种方式,那么可能是调用方读取超时异常)。webmethod
syncronized
根据预期行为,有很多不同的解决方案,甚至可以实现自己的解决方案或现有解决方案。从技术上讲,这被称为 “速率限制” 。bucket4j 是您可以使用的一种实现。 这是一种你自己可以实现的简单方法(不完美,你可以通过学习和使用我们在 Java 并发包中内置的同步器来使其完美)
- 在控制器类中引入一个字段,或者任何具有
Semaphore semaphore = new Semaphore(10)
webmethod
然后在 Web 方法中使用这种逻辑
if (semaphore.tryAcquire())
{
try
{
// your call to calculate task and return the result
}
finally
{
semaphore.release();
}
}
else
{
//handle or throw error , this is the 11th call while 10 ongoing requests are there
}
我相信你需要的是一个线程池。它们就是为此目的而建造的。您可以配置池中的线程数,并让池处理执行对计算器 Bean 的调用。您可以在 Google 上搜索的类是 ExecutorService 或 ThreadPoolExecutor。下面是 pseudo/Kotlin/Java 中的一个示例。如果您不需要实时响应,这将很好地工作。您可以让客户端代码发起请求,在单独的调用中查找结果,但我不知道您的业务需求。
执行人服务
定义线程池、池中的线程数和其他一些基础知识。
private val executorService: ExecutorService = ThreadPoolExecutor(
1, 1, 0L, TimeUnit.MILLISECONDS,
LinkedBlockingQueue<Runnable>()
)
现在,在控制器或 Web 请求处理程序中,告诉执行程序执行您的计算器 Bean 代码。它会将所有这些调用发送到池队列,并且您定义的受约束线程将处理它们。
处理请求
@WebMethod(operationName="calculateWebMethod", action="calculateWebMethod")
public calculateWebMethodResponse calculateWebMethod(
@WebParam(name="param1") String param1,
@WebParam(name="param2") String param2,
...
) {
executorService.execute {
long webMethodResult = CalculateBean.CalculateTask(...params);
return webMethodResult;
}
}
评论