Java 在servlet环境中处理批处理作业的线程
我有一个SpringMVC,Hibernate,(Postgres9DB)Web应用程序。管理员用户可以发送一个请求来处理近200000条记录(每条记录都是通过联接从各个表收集的)。每周或每月(或当数据达到约200000/100000条记录的限制时)都会要求进行此类操作。在数据库端,我正确地实现了批处理Java 在servlet环境中处理批处理作业的线程,java,servlets,spring-mvc,threadpool,batch-processing,Java,Servlets,Spring Mvc,Threadpool,Batch Processing,我有一个SpringMVC,Hibernate,(Postgres9DB)Web应用程序。管理员用户可以发送一个请求来处理近200000条记录(每条记录都是通过联接从各个表收集的)。每周或每月(或当数据达到约200000/100000条记录的限制时)都会要求进行此类操作。在数据库端,我正确地实现了批处理 问题:这样一个长时间运行的请求会阻塞服务器线程,这会导致普通用户受到影响 要求:此请求的高响应时间不是问题。所需要的是不要让其他用户因为这个耗时的过程而受苦 我的解决方案: 使用Sprin
- 问题:这样一个长时间运行的请求会阻塞服务器线程,这会导致普通用户受到影响
- 要求:此请求的高响应时间不是问题。所需要的是不要让其他用户因为这个耗时的过程而受苦
- 我的解决方案: 使用Spring taskExecutor抽象实现线程池。因此,我可以用5或6个线程初始化线程池,并将200000条记录分成更小的块,比如每个块大小为1000条。我可以在这些区块中排队。为了进一步让普通用户能够更快地访问数据库,也许我可以让每个可运行线程睡眠2或3秒。 我看到这种方法的优点是:与一次性执行一个巨大的db交互请求不同,我们有一个跨越更长时间的异步设计。因此,其行为类似于多个普通用户请求
再次强调:完全处理所有记录的时间无关紧要,所需的是在此期间访问web应用程序的普通用户不应受到任何影响。您可以并行处理任务,并等待所有任务完成后再返回呼叫。为此,您希望使用Java标准中自5.0以来提供的 简而言之,您可以使用容器的服务定位器来创建ExecutorCompletionService的实例
ExecutorCompletionService<List<MyResult>> queue = new ExecutorCompletionService<List<MyResult>>(executor);
// do this in a loop
queue.submit(aCallable);
//after looping
queue.take().get(); //take will block till all threads finish
ExecutorCompletionService队列=新的ExecutorCompletionService(executor);
//循环执行此操作
排队。提交(不可更改);
//循环后
queue.take().get()//take将阻塞直至所有螺纹完成
如果您不想等待,那么可以在后台处理作业,而不阻塞当前线程,但是需要某种机制在作业完成时通知客户端。这可以通过JMS实现,或者如果您有一个ajax客户端,它可以轮询更新
Quartz也有一个作业调度机制,但Java提供了一种标准方法
编辑:
我可能误解了这个问题。如果您不希望更快的响应,而是希望限制CPU,请使用此方法
您可以创建一个类似于PollingThread的内部类,其中包含每个作业的java.util.UUID和PollingThread数量的批在外部类中定义。这将永远持续下去,并且可以调整以使您的CPU能够自由处理其他请求
class PollingThread implements Runnable {
@SuppressWarnings("unchecked")
public void run(){
Thread.currentThread().setName("MyPollingThread");
while (!Thread.interrupted()) {
try {
synchronized (incomingList) {
if (incomingList.size() == 0) {
// incoming is empty, wait for some time
} else {
//clear the original
list = (LinkedHashSet<UUID>)
incomingList.clone();
incomingList.clear();
}
}
if (list != null && list.size() > 0) {
processJobs(list);
}
// Sleep for some time
try {
Thread.sleep(seconds * 1000);
} catch (InterruptedException e) {
//ignore
}
} catch (Throwable e) {
//ignore
}
}
}
}
类PollingThread实现可运行{
@抑制警告(“未选中”)
公开募捐{
Thread.currentThread().setName(“MyPollingThread”);
而(!Thread.interrupted()){
试一试{
已同步(输入列表){
if(incomingList.size()==0){
//传入为空,请等待一段时间
}否则{
//清除原始文件
列表=(LinkedHashSet)
incomingList.clone();
incomingList.clear();
}
}
if(list!=null&&list.size()>0){
处理工作(名单);
}
//睡一会儿
试一试{
线程睡眠(秒*1000);
}捕捉(中断异常e){
//忽略
}
}捕获(可丢弃的e){
//忽略
}
}
}
}
您可以将任务并行化,等待所有任务完成后再返回呼叫。为此,您希望使用Java标准中自5.0以来提供的
简而言之,您可以使用容器的服务定位器来创建ExecutorCompletionService的实例
ExecutorCompletionService<List<MyResult>> queue = new ExecutorCompletionService<List<MyResult>>(executor);
// do this in a loop
queue.submit(aCallable);
//after looping
queue.take().get(); //take will block till all threads finish
ExecutorCompletionService队列=新的ExecutorCompletionService(executor);
//循环执行此操作
排队。提交(不可更改);
//循环后
queue.take().get()//take将阻塞直至所有螺纹完成
如果您不想等待,那么可以在后台处理作业,而不阻塞当前线程,但是需要某种机制在作业完成时通知客户端。这可以通过JMS实现,或者如果您有一个ajax客户端,它可以轮询更新
Quartz也有一个作业调度机制,但Java提供了一种标准方法
编辑:
我可能误解了这个问题。如果您不希望更快的响应,而是希望限制CPU,请使用此方法
您可以创建一个类似于PollingThread的内部类,其中包含每个作业的java.util.UUID和PollingThread数量的批在外部类中定义。这将永远持续下去,并且可以调整以使您的CPU能够自由处理其他请求
class PollingThread implements Runnable {
@SuppressWarnings("unchecked")
public void run(){
Thread.currentThread().setName("MyPollingThread");
while (!Thread.interrupted()) {
try {
synchronized (incomingList) {
if (incomingList.size() == 0) {
// incoming is empty, wait for some time
} else {
//clear the original
list = (LinkedHashSet<UUID>)
incomingList.clone();
incomingList.clear();
}
}
if (list != null && list.size() > 0) {
processJobs(list);
}
// Sleep for some time
try {
Thread.sleep(seconds * 1000);
} catch (InterruptedException e) {
//ignore
}
} catch (Throwable e) {
//ignore
}
}
}
}
类轮询