下面是根据你提供的代码,为你总结的异步任务添加和管理的笔记:
异步任务管理:使用 @Async 与 ExecutorService
在 Java 中,异步任务的处理可以极大提高应用程序的性能,特别是在需要进行 IO 密集型操作(例如数据库查询、API 调用等)时。Spring 提供了 @Async 注解来支持异步执行,但有时我们可能需要使用更灵活的线程池和控制方式,像你代码中的 ExecutorService 就是一个很好的示例。
异步任务的基本步骤:
标记异步方法: 使用
@Async注解标记一个方法为异步执行的方法。这样,方法就会在另一个线程中执行,而不会阻塞主线程。异步方法可以返回Future、CompletableFuture或void(不需要返回值)。java@Async public void newsEventStock(int category) { // 异步方法的逻辑 }创建线程池: 在上面的代码中,
ExecutorService是用来管理异步任务的线程池。你使用了Executors.newFixedThreadPool(summaryPoolSize)来创建一个固定大小的线程池,确保同时有summaryPoolSize个线程处理异步任务。javaExecutorService asyncExecutor = Executors.newFixedThreadPool(summaryPoolSize);你可以通过
ExecutorService来管理线程池的生命周期和控制并发数。跟踪任务进度: 为了能够追踪异步任务的进度,代码中使用了
ProgressTracker类来跟踪任务的进度。每当一个任务完成时,调用tracker.increment()方法更新进度。javaProgressTracker tracker = new ProgressTracker(totalTasks, "资讯", asyncExecutor); tracker.start();这种方式可以让你在所有异步任务完成后,得到一个明确的进度反馈。
使用
CompletableFuture管理异步任务:CompletableFuture是一种更灵活的异步执行模型,允许你非阻塞地执行异步操作,并且可以通过then方法连接多个操作。在代码中,
CompletableFuture.runAsync被用来执行每个异步任务。每个任务执行完后,它会执行tracker.increment()来更新进度,并且处理数据库插入、API 调用等逻辑。javaList<CompletableFuture<Void>> futures = stocks.stream() .map(stock -> CompletableFuture.runAsync(() -> { // 异步执行的任务逻辑 }, asyncExecutor)) .toList();这里的
futures是一个CompletableFuture对象的列表,它代表每个异步任务。你可以通过CompletableFuture.allOf()方法等待所有异步任务完成。等待所有任务完成: 通过
CompletableFuture.allOf(futures.toArray(new CompletableFuture[0])).join(),等待所有异步任务完成。join()方法会阻塞当前线程直到所有任务执行完毕。javaCompletableFuture.allOf(futures.toArray(new CompletableFuture[0])).join();
代码解析:
开始异步任务: 在
newsEventStock方法开始时,通过调用stockData.listStockFromCache()获取所有股票的列表,并计算出任务总数。创建线程池和进度追踪器: 使用固定大小的线程池
asyncExecutor来控制并发任务数,并通过ProgressTracker追踪任务进度。异步执行每个任务: 使用 Java 8 的
stream()和map()来异步执行每个股票的处理任务。每个股票会被传入一个CompletableFuture.runAsync()方法中,并在该任务中执行 API 请求、数据库插入等操作。更新任务状态: 每个任务完成时,会更新进度追踪器的进度,确保所有任务的执行进度被正确记录。
等待所有任务完成:
CompletableFuture.allOf(futures.toArray(new CompletableFuture[0])).join()会等待所有异步任务完成。join()方法会确保方法只有在所有异步操作完成后才返回。
总结:
- 异步执行任务: 使用
@Async或CompletableFuture来并行执行耗时操作,可以大大提高系统的响应速度和吞吐量。 - 线程池管理: 通过
ExecutorService来管理线程池,可以控制并发任务数,并且避免创建过多线程造成系统资源压力。 - 任务进度追踪: 使用
ProgressTracker来跟踪异步任务的执行进度,帮助开发者了解任务执行的情况。 - 等待任务完成: 使用
CompletableFuture.allOf()等方法来等待所有异步任务执行完成,从而在所有任务完成后进行后续操作。
优化建议:
- 线程池的配置:确保
summaryPoolSize的大小与服务器的硬件资源(如 CPU 核数)相匹配,避免创建过多线程导致线程上下文切换过于频繁,影响性能。 - 异常处理:你已经很好地处理了异常,但可以考虑使用
CompletableFuture.exceptionally()方法处理任务中的异常,这样可以确保任务的失败不会影响其他任务的执行。 - 资源回收:如果不再使用
ExecutorService,应该确保在适当的时机关闭线程池,以避免资源泄露。可以使用asyncExecutor.shutdown()来优雅地关闭线程池。