我有一个JAX-RS / Jersey Rest API获取请求,需要在单独的线程中执行额外的工作,但我不确定是否建议使用线程池。我希望这个API有很多请求(每天几千),但我在后台只有一个额外的工作。
每次像这样创建一个新线程会不好?任何意见,将不胜感激。我之前没有使用过ThreadPool。
@Get
@Path("/myAPI")
public Response myCall() {
// call load in the background
load();
...
// do main job here
mainJob();
...
}
private void load() {
new Thread(new Runnable() {
@Override
public void run() {
doSomethingInTheBackground();
}
}).start();
}
修改 只是为了澄清。我只需要一个额外的工作就可以在后台运行。这项工作将调用另一个API来记录一些信息,这就是它。但它必须为每个请求执行此操作,我不需要等待响应。这就是为什么我想在新的后台线程中这样做的原因。
EDIT2: 所以这就是我现在提出来的。任何人都可以告诉我,如果这似乎没问题(它在本地工作),如果我需要关闭执行程序(请参阅我在代码中的评论)?
// Configuration class
@Bean (name = "executorService")
public ExecutorService executorService() {
return Executors.newFixedThreadPool(Runtime.getRuntime().availableProcessors() + 1);
}
// Some other class
@Qualifier("executorService")
@Autowired
private ExecutorService executorService;
....
private void load() {
executorService.submit(new Runnable() {
@Override
public void run() {
doSomethingInTheBackground();
}
});
// If I enable this I will get a RejectedExecutionException
// for a next request.
// executorService.shutdown();
}
答案 0 :(得分:4)
Threadpool是解决这个问题的好方法,原因有两个:
1)您将重用池中的现有线程,减少开销 2)更重要的是,如果系统受到攻击,您的系统将不会陷入困境,并且由于池的大小将被预设,某些方尝试立即启动数以万计的会话。
使用线程池并不复杂。有关线程池的更多信息,请参阅here。还要看看oracle documentation。
答案 1 :(得分:1)
我建议不使用您提到的方法,而是使用JMS队列。您可以轻松地在应用程序中嵌入ActiveMQ实例。首先在后台创建一个或多个单独的使用者线程,以从队列中获取作业。
然后,当收到请求时,只需在JMS队列上按下包含作业详细信息的消息。这是一个更好的架构,比摆弄低级线程或线程池更具可扩展性。
另请参阅:this answer和the activeMQ site。
答案 2 :(得分:1)
听起来你根本不需要创建多个线程。 (虽然我可能错了,但我不知道你的任务的具体细节。)
您是否可以创建一个完成后台工作的线程,并为该线程提供LinkedBlockingQueue
来存储doSomethingInTheBackground
调用的参数?
如果后台任务立即启动,即使服务器负载很重,这个解决方案也不会起作用。但是例如对于我最近的任务(从外部检索文本,将它们返回到API调用者,然后将文本延迟添加到SOLR层)这是一个非常好的解决方案。