Java 如何使用线程池并行单个quartz作业?

Java 如何使用线程池并行单个quartz作业?,java,multithreading,quartz-scheduler,job-scheduling,Java,Multithreading,Quartz Scheduler,Job Scheduling,在我的Spring boot应用程序中,我有一个quartz计划的任务,当每5分钟触发一次时,通过一种方法将项目从一个大列表发送到一些Web服务 我想知道我的发送过程(单一发送方法)是否可以并行化? 我想要的是,例如,当10000个条目列表来自db,线程池中的线程将同时工作以发送该列表中的所有记录,并且在发送所有记录之后,作业将完成 我在代码下面尝试的我设置了一个线程池大小为5的ThreadPoolTaskExecutor。 然而,当我执行并检查作业日志时,它说作业在几秒钟内完成,但发送所有数据

在我的Spring boot应用程序中,我有一个quartz计划的任务,当每5分钟触发一次时,通过一种方法将项目从一个大列表发送到一些Web服务

我想知道我的发送过程(单一发送方法)是否可以并行化? 我想要的是,例如,当10000个条目列表来自db,线程池中的线程将同时工作以发送该列表中的所有记录,并且在发送所有记录之后,作业将完成

我在代码下面尝试的我设置了一个线程池大小为5的
ThreadPoolTaskExecutor
。 然而,当我执行并检查作业日志时,它说作业在几秒钟内完成,但发送所有数据需要几分钟。它继续正常工作,但工作似乎在几秒钟内完成。它可能会说,在所有线程都设置好之后,作业就完成了。这是我避免的,因为我需要知道作业执行时间和日志

@Autowired
MyService myService;

@NonTransactionalService 
public class MySenderService{

    ThreadPoolTaskExecutor taskExecutor = new ThreadPoolTaskExecutor();
    taskExecutor.setCorePoolSize(5);
    taskExecutor.setMaxPoolSize(5);
    taskExecutor.initialize();

    public void sendAll(){
        List<Long> largeList = someMethod();
        largeList.stream().forEach(i -> {
            taskExecutor.execute(new Runnable() {
                @Override
                public void run() {
                    myService.send(i);
                }
            });
        }
    }
}
@Autowired
我的服务我的服务;
@非事务服务
公共类MySenderService{
ThreadPoolTaskExecutor taskExecutor=新的ThreadPoolTaskExecutor();
taskExecutor.setCorePoolSize(5);
taskExecutor.setMaxPoolSize(5);
taskExecutor.initialize();
公共void sendAll(){
List largeList=someMethod();
largeList.stream()forEach(i->{
taskExecutor.execute(新的Runnable(){
@凌驾
公开募捐{
myService.send(i);
}
});
}
}
}
那么,如何在一个作业中对多个工作人员运行此发送方法呢?

设置多个相同作业以通过相同方法发送相同列表是否是一种好做法?

您可以尝试使用通量,IMHO是一种需要更少代码的解决方案:

        ThreadPoolTaskExecutor taskExecutor = new ThreadPoolTaskExecutor();
        taskExecutor.setCorePoolSize(5);
        taskExecutor.setMaxPoolSize(5);
        taskExecutor.initialize();

        List<Integer> largeList = someMethod();
        System.out.println(largeList);
        Flux.fromStream(largeList.stream())
                .parallel(5)
                .runOn(Schedulers.fromExecutor(taskExecutor))
                .subscribe( x -> { System.out.println(x);});

        taskExecutor.shutdown();
ThreadPoolTaskExecutor taskExecutor=新的ThreadPoolTaskExecutor();
taskExecutor.setCorePoolSize(5);
taskExecutor.setMaxPoolSize(5);
taskExecutor.initialize();
List largeList=someMethod();
系统输出打印LN(largeList);
Flux.fromStream(largeList.stream())
.平行(5)
.runOn(调度程序.fromExecutor(任务执行器))
.subscribe(x->{System.out.println(x);});
taskExecutor.shutdown();

别忘了关闭TaskExecutor,但正如@M.Deinum所说,最好在其他地方创建它,并将其注入到您的服务中。

您的工作已经找到(从Quartz的角度来看),但它现在在后台运行。您没有任何改进。相反,将yuor largeList分成x个部分(可能是5个)然后启动5个单独的任务,每个任务在列表的一部分上运行。是的,当我的
sendAll()
方法完成时,它会显示作业已完成。所以-我很好奇-如果我循环一个
while(taskExecutor.getActiveCount()!=0),会怎么样
在sendAll方法完成之前,当它相等时,我让该方法完成?这仍然是一个糟糕的做法吗?总而言之,我想知道正确的方法是您上面建议的方法吗?谢谢您的回答。@M.DeinumSplit您的列表,使用
CompletableFuture.SupplySync(,taskExecutor)
;这将返回一个
CompletableFuture
。将它们收集到一个列表中。准备好所有工作块后,使用
CompletableFuture.allOf
加入它们。然后在生成的
CompletableFuture
上调用
join
,这将等待所有工作完成。不要依赖于
活动计数作为Ideally您想注入
TaskExecutor`并且没有任何东西阻止您重用它。如果您需要更多的控制,我建议使用Spring Batch,这样做很容易。感谢您的帮助,我将尝试您建议的解决方案。我将不断更新结果。@M.Deinum