Spring Boot 定时任务以及异步任务的实现

news2025/3/17 7:01:16

一、定时任务

在 Spring Boot 中,实现定时任务非常简单,主要通过 @Scheduled 注解和 TaskScheduler 接口来实现。以下是实现定时任务的详细步骤和方法:

  1. 启用定时任务支持
    • 在 Spring Boot 应用中,首先需要启用定时任务支持。可以通过在配置类或主应用类上添加 @EnableScheduling 注解来实现。
    import org.springframework.boot.SpringApplication;
    import org.springframework.boot.autoconfigure.SpringBootApplication;
    import org.springframework.scheduling.annotation.EnableScheduling;
    
    @SpringBootApplication
    @EnableScheduling // 启用定时任务支持
    public class MyApplication {
    	public static void main(String[] args) {
        	SpringApplication.run(MyApplication.class, args);
    	}
    }
    
  2. 使用 @Scheduled 注解创建定时任务
    • @Scheduled 注解用于标记一个方法为定时任务。可以通过 cron 表达式、固定延迟(fixedDelay)、固定速率(fixedRate)等方式配置任务的执行时间。
      • Cron 表达式
        • Cron 表达式:是一种灵活的时间配置方式,支持秒、分、时、日、月、周等字段。
        import org.springframework.scheduling.annotation.Scheduled;
        import org.springframework.stereotype.Component;
        
        @Component
        public class MyScheduledTasks {
        
        	@Scheduled(cron = "0 * * * * ?") // 每分钟执行一次
        	public void taskWithCron() {
        		System.out.println("Cron 任务执行: " + System.currentTimeMillis());
        	}
        }
        
      • 固定延迟(fixedDelay)
        • fixedDelay:表示任务执行完成后,延迟指定时间再执行下一次任务。
        @Scheduled(fixedDelay = 5000) // 每次任务完成后,延迟 5 秒再执行下一次
        public void taskWithFixedDelay() {
        	System.out.println("FixedDelay 任务执行: " + System.currentTimeMillis());
        }
        
      • 固定速率(fixedRate)
        • fixedRate:表示任务以固定的速率执行,无论上一次任务是否完成。
        @Scheduled(fixedRate = 3000) // 每 3 秒执行一次
        public void taskWithFixedRate() {
        	System.out.println("FixedRate 任务执行: " + System.currentTimeMillis());
        }
        
  3. 配置定时任务线程池
    • 创建自定义线程池
      • Spring Boot 会自动将 @Scheduled 注解的任务绑定到 ThreadPoolTaskScheduler 自定义线程池中。
    import org.springframework.context.annotation.Bean;
    import org.springframework.context.annotation.Configuration;
    import org.springframework.scheduling.concurrent.ThreadPoolTaskScheduler;
    
    @Configuration
    public class SchedulerConfig {
    
    	@Bean
    	public ThreadPoolTaskScheduler taskScheduler() {
        	ThreadPoolTaskScheduler scheduler = new ThreadPoolTaskScheduler();
        	scheduler.setPoolSize(10); // 设置线程池大小
        	scheduler.setThreadNamePrefix("MyScheduler-"); // 设置线程名前缀
        	return scheduler;
    	}
    }
    

二、异步任务

在 Spring Boot 中,实现异步任务非常简单,主要通过 @Async 注解和 TaskExecutor 接口来实现。异步任务适用于需要并发执行的场景,例如发送邮件、处理文件、调用外部 API 等。

  1. 启用异步任务支持

    • 在 Spring Boot 应用中,首先需要启用异步任务支持。可以通过在配置类或主应用类上添加 @EnableAsync 注解来实现。
    import org.springframework.boot.SpringApplication;
    import org.springframework.boot.autoconfigure.SpringBootApplication;
    import org.springframework.scheduling.annotation.EnableAsync;
    
    @SpringBootApplication
    @EnableAsync // 启用异步任务支持
    public class MyApplication {
    	public static void main(String[] args) {
        	SpringApplication.run(MyApplication.class, args);
    	}
    }
    
  2. 使用 @Async 注解创建异步任务

    • @Async 注解用于标记一个方法为异步任务。被标记的方法会在独立的线程中执行。
    import org.springframework.scheduling.annotation.Async;
    import org.springframework.stereotype.Service;
    
    @Service
    public class MyAsyncService {
    
    	@Async // 标记为异步方法
    	public void asyncTask() {
        	System.out.println("异步任务开始执行,线程: " + Thread.currentThread().getName());
        	try {
            	Thread.sleep(5000); // 模拟耗时操作
        	} catch (InterruptedException e) {
            	e.printStackTrace();
        	}
        	System.out.println("异步任务执行完成,线程: " + Thread.currentThread().getName());
    	}
    }
    
  3. 配置线程池

    • 默认情况下,Spring Boot 使用 SimpleAsyncTaskExecutor 执行异步任务,每次都会创建一个新线程。为了更高效地管理线程,可以配置自定义线程池。
      • 使用 ThreadPoolTaskExecutor 配置线程池
        import org.springframework.context.annotation.Bean;
        import org.springframework.context.annotation.Configuration;
        import org.springframework.scheduling.concurrent.ThreadPoolTaskExecutor;
        
        import java.util.concurrent.Executor;
        
        @Configuration
        public class AsyncConfig {
        
        	@Bean(name = "taskExecutor")
        	public Executor taskExecutor() {
        		ThreadPoolTaskExecutor executor = new ThreadPoolTaskExecutor();
        		executor.setCorePoolSize(10); // 核心线程数
        		executor.setMaxPoolSize(20); // 最大线程数
        		executor.setQueueCapacity(50); // 队列容量
        		executor.setThreadNamePrefix("Async-"); // 线程名前缀
        		executor.initialize();
        		return executor;
        	}
        }
        
      • 在 @Async 注解中指定线程池的名称
        @Async("taskExecutor") // 指定线程池
        public void asyncTask() {
        	System.out.println("异步任务执行,线程: " + Thread.currentThread().getName());
        }
        
  4. 处理异步任务的返回值

    • 如果异步方法有返回值,可以使用 Future 或 CompletableFuture 来获取结果。
      • 使用 Future,调用方可以通过 Future.get() 方法获取结果
        import org.springframework.scheduling.annotation.Async;
        import org.springframework.stereotype.Service;
        
        import java.util.concurrent.Future;
        
        @Service
        public class MyAsyncService {
        
        	@Async
        	public Future<String> asyncTaskWithReturn() {
        		System.out.println("异步任务开始执行,线程: " + Thread.currentThread().getName());
        		try {
        			Thread.sleep(5000); // 模拟耗时操作
        		} catch (InterruptedException e) {
        			e.printStackTrace();
        		}
        		return new AsyncResult<>("任务完成");
        	}
        }
        
        // 调用 MyAsyncService 的异步方法
        Future<String> future = myAsyncService.asyncTaskWithReturn();
        // 阻塞等待结果
        String result = future.get(); 
        
      • 使用 CompletableFuture,Java 8 引入的增强版 Future,支持更灵活的任务编排。
        import org.springframework.scheduling.annotation.Async;
        import org.springframework.stereotype.Service;
        
        import java.util.concurrent.CompletableFuture;
        
        @Service
        public class MyAsyncService {
        
        	@Async
        	public CompletableFuture<String> asyncTaskWithCompletableFuture() {
        		System.out.println("异步任务开始执行,线程: " + Thread.currentThread().getName());
        		try {
        			Thread.sleep(5000); // 模拟耗时操作
        		} catch (InterruptedException e) {
        			e.printStackTrace();
        		}
        		return CompletableFuture.completedFuture("任务完成");
        	}
        }
        
        CompletableFuture<String> future = myAsyncService.asyncTaskWithCompletableFuture();
        future.thenAccept(result -> System.out.println("任务结果: " + result));
        
  5. 异常处理

    • 异步任务中的异常不会传播到调用方,需要通过以下方式处理:
      • 自定义异常处理器,实现 AsyncUncaughtExceptionHandler 接口,处理未捕获的异常。
        import org.springframework.aop.interceptor.AsyncUncaughtExceptionHandler;
        import org.springframework.context.annotation.Configuration;
        import org.springframework.scheduling.annotation.AsyncConfigurer;
        import org.springframework.scheduling.annotation.EnableAsync;
        
        import java.lang.reflect.Method;
        import java.util.concurrent.Executor;
        
        @Configuration
        @EnableAsync
        public class AsyncConfig implements AsyncConfigurer {
        
        	@Override
        	public Executor getAsyncExecutor() {
        		ThreadPoolTaskExecutor executor = new ThreadPoolTaskExecutor();
        		executor.setCorePoolSize(10);
        		executor.setMaxPoolSize(20);
        		executor.setQueueCapacity(50);
        		executor.setThreadNamePrefix("Async-");
        		executor.initialize();
        		return executor;
        	}
        
        	@Override
        	public AsyncUncaughtExceptionHandler getAsyncUncaughtExceptionHandler() {
        		return (ex, method, params) -> {
        			System.err.println("异步任务异常: " + ex.getMessage());
        			System.err.println("方法: " + method.getName());
        		};
        	}
        }
        
      • 在异步方法内部捕获并处理异常。
        @Async
        public void asyncTaskWithException() {
        	try {
        		// 业务逻辑
            } catch (Exception e) {
        		System.err.println("捕获异常: " + e.getMessage());
        	}
        }
        

本文来自互联网用户投稿,该文观点仅代表作者本人,不代表本站立场。本站仅提供信息存储空间服务,不拥有所有权,不承担相关法律责任。如若转载,请注明出处:http://www.coloradmin.cn/o/2316474.html

如若内容造成侵权/违法违规/事实不符,请联系多彩编程网进行投诉反馈,一经查实,立即删除!

相关文章

Vue 生命周期详解:从创建到销毁的全过程

Vue.js 是一个流行的前端框架&#xff0c;它通过组件化的方式帮助开发者构建用户界面。在 Vue 中&#xff0c;每个组件实例都有其生命周期&#xff0c;从创建、挂载、更新到销毁&#xff0c;Vue 提供了一系列的生命周期钩子函数&#xff0c;允许我们在组件的不同阶段执行自定义…

计算机基础:二进制基础12,十进制数转换为十六进制

专栏导航 本节文章分别属于《Win32 学习笔记》和《MFC 学习笔记》两个专栏&#xff0c;故划分为两个专栏导航。读者可以自行选择前往哪个专栏。 &#xff08;一&#xff09;WIn32 专栏导航 上一篇&#xff1a;计算机基础&#xff1a;二进制基础11&#xff0c;十六进制的位基…

SpringCloud系列教程(十四):Sentinel持久化

Sentinel之前已经搭建和应用成功了&#xff0c;但是它有一个很大的缺点就是官方没有提供持久化的方案&#xff0c;从项目源码上看感觉这款工具也没有完成的太好&#xff0c;所以需要我们去对它进行二次开发。要补充的功能大概如下&#xff1a; 1、将Sentinel接入nacos中&#…

Slider,InputField,Scroll View,Scrollbar及Layout组件

Slider组件 Fill Rect:填充滑动条选中区域的背景图部分 Handle Rect:滑动条的球 Direction:滑动条的滑动方向 Min Value:起始位置的数值&#xff08;浮点数&#xff09; Max Value:结束位置的数值&#xff08;浮点数&#xff09; Whole Numbers:必须为整数&#xff08;布尔…

ollama注册自定义模型(GGUF格式)

文章目录 ollama注册自定义模型&#xff08;GGUF格式&#xff09;下载模型注册模型(GGUF格式) ollama注册自定义模型&#xff08;GGUF格式&#xff09; 需要全程开启ollama nohup ollama serve > ollama.log 2>&1 &需要注意&#xff0c;尽管手动下载的GGUF格式模…

HarmonyOS NEXT 声明式UI语法学习笔记-创建自定义组件

基础语法概述 ArkTS的基本组成 装饰器&#xff1a;用于装饰类、结构、方法以及变量&#xff0c;并赋予其特殊含义。如上图都是装饰器&#xff0c;Component表示自定义组件&#xff0c;Entry表示表示自定义组件的入口组件&#xff0c;State表示组件中的状态变量&#xff0c;当状…

97.HarmonyOS NEXT跑马灯组件教程:基础概念与架构设计

温馨提示&#xff1a;本篇博客的详细代码已发布到 git : https://gitcode.com/nutpi/HarmonyosNext 可以下载运行哦&#xff01; HarmonyOS NEXT跑马灯组件教程&#xff1a;基础概念与架构设计 1. 跑马灯组件概述 跑马灯&#xff08;Marquee&#xff09;是一种常见的UI组件&a…

81.HarmonyOS NEXT 状态管理与响应式编程:@Observed深度解析

温馨提示&#xff1a;本篇博客的详细代码已发布到 git : https://gitcode.com/nutpi/HarmonyosNext 可以下载运行哦&#xff01; HarmonyOS NEXT 状态管理与响应式编程&#xff1a;Observed深度解析 文章目录 HarmonyOS NEXT 状态管理与响应式编程&#xff1a;Observed深度解析…

股指期货有卖不出去的时候吗?

在股指期货的交易世界里&#xff0c;很多人都有这样的疑问&#xff1a;股指期货会不会有卖不出去的时候呢&#xff1f;答案是会的&#xff0c;下面咱们就来详细唠唠为啥会出现这种情况。 市场极端行情下难以卖出 1.跌停限制&#xff1a;股指期货和股票一样&#xff0c;也有涨…

开发、科研、日常办公工具汇总(自用,持续更新)

主要记录汇总一下自己平常会用到的网站工具&#xff0c;方便查阅。 update&#xff1a;2025/2/11&#xff08;开发网站补一下&#xff09; update&#xff1a;2025/2/21&#xff08;补充一些AI工具&#xff0c;刚好在做AI视频相关工作&#xff09; update&#xff1a;2025/3/7&…

HTML5 drag API实现列表拖拽排序

拖拽API&#xff08;Drag and Drop API&#xff09;是HTML5提供的一组功能&#xff0c;使得在网页上实现拖放操作变得更加简单和强大。这个API允许开发者为网页元素添加拖拽功能&#xff0c;用户可以通过鼠标将元素拖动并放置到指定的目标区域。 事件类型 dragstart&#xff1…

改变一生的思维模型【11】升维

升维思维模型&#xff1a;突破认知局限的破局法则 一、定义与核心逻辑 升维思维是通过增加分析维度&#xff0c;将问题投射到更高认知层次寻找解决方案的思考方式。其本质是跳出原有竞争维度&#xff0c;在更广阔的空间重构游戏规则。核心逻辑在于&#xff1a;当低维战场陷入…

【动手学深度学习】#2线性神经网络

主要参考学习资料&#xff1a; 《动手学深度学习》阿斯顿张 等 著 【动手学深度学习 PyTorch版】哔哩哔哩跟李牧学AI 目录 2.1 线性回归2.1.1 线性回归的基本元素线性模型损失函数解析解随机梯度下降 2.1.3 最大似然估计 2.2 线性回归从零开始实现2.2.1 生成数据集2.2.2 读取数…

计算机网络——NAT

一、什么是NAT&#xff1f; NAT&#xff08;Network Address Translation&#xff0c;网络地址转换&#xff09; 是一种将 私有IP地址 与 公有IP地址 相互映射的技术&#xff0c;主要用于解决IPv4地址不足的问题。它像一名“翻译官”&#xff0c;在数据包经过路由器或防火墙时…

同一子网通信

添加交换机后的通信流程 1. 同一子网内&#xff08;使用交换机&#xff09; 判断是否在同一子网&#xff1a; 主机A通过子网掩码判断主机B的IP地址是否属于同一子网。若在同一子网&#xff0c;主机A需要通过ARP获取主机B的MAC地址。 ARP请求&#xff08;广播&#xff09;&…

IntelliJ IDEA 快捷键系列:重命名快捷键详解

目录 引言一、默认重命名快捷键1. Windows 系统‌2. Mac 系统‌ 二、操作步骤与技巧1. 精准选择重命名范围‌2. 智能过滤无关内容‌ 三、总结 引言 在代码重构中&#xff0c;‌重命名变量、类、方法‌ 是最常用的操作之一。正确使用快捷键可以极大提升开发效率。本文针对 ‌Ma…

零基础掌握分布式ID生成:从理论到实战的完整指南 [特殊字符]

一、为什么需要分布式ID&#xff1f; &#x1f914; 在单机系统中&#xff0c;使用数据库自增ID就能满足需求。但在分布式系统中&#xff0c;多个服务节点同时生成ID时会出现以下问题&#xff1a; ID冲突&#xff1a;不同节点生成相同ID 扩展困难&#xff1a;数据库自增ID无法…

使用python反射,实现pytest读取yaml并发送请求

pytest yaml yaml - feature: 用户模块story: 登录title: 添加用户request:method: POSTurl: /system/user/listheaders: nullparams: nullvalidate: nullread_yaml_all def read_yaml_all(path):with open(path, r, encodingutf-8) as f:value yaml.safe_load(f)return v…

Matlab 汽车悬架系统动力学建模与仿真

1、内容简介 略 Matlab 170-汽车悬架系统动力学建模与仿真 可以交流、咨询、答疑 2、内容说明 略 本文对题目给定的1/2汽车四自由度模型&#xff0c;建立状态空间模型进行系统分析&#xff0c;并通过MATLAB仿真对系统进行稳定性、可控可观测性分析&#xff0c;对得的结果进行…

专访数势科技谭李:智能分析 Agent 打通数据平权的最后一公里

作者|斗斗 编辑|皮爷 出品|产业家 伦敦塔桥下的泰晤士河底&#xff0c;埋藏着工业革命的隐秘图腾——布鲁内尔设计的隧道盾构机。在19世纪城市地下轨道建设的过程中&#xff0c;这个直径11米的钢铁巨兽没有选择拓宽河道&#xff0c;而是开创了地下通行的新维度。 “我们不…