学习笔记之Java的异步实现方式
学习笔记之Java的异步实现方式
异步的八种实现方式:1.线程Thread 2.Future(少用) 3.异步框架CompletableFuture(是Future的升级版) 4.Spring注解@Async(重点) 5.Spring ApplicationEvent 6.消息队列 7.第三方异步框架,比如Hutool(糊涂库) 的 ThreadUti
-
Guava异步
Executor线程池,也叫任务调度器。大部分异步实现都是new这个对象,然后调用这个对象的方法。
这里我挑选几个重点讲吧,以用户下单的场景为例子:
这里发送短信要等赠送积分执行完才可以开始执行,其实发送短信和赠送积分没有先后关系,可以异步执行的
所以改进后是这样:
线程异步
public class AsyncThread extends Thread {
@Override
public void run() {
System.out.println("Current thread name:" + Thread.currentThread().getName() + " Send email success!");
}
public static void main(String[] args) {
AsyncThread asyncThread = new AsyncThread();
asyncThread.run();
}
}
如果每次都创建一个Thread
线程,频繁的创建、销毁,浪费系统资源,我们可以采用线程池:
private ExecutorService executorService = Executors.newCachedThreadPool();
public void fun() {
executorService.submit(new Runnable() {
@Override
public void run() {
log.info("执行业务逻辑...");
}
});
}
可以将业务逻辑封装到Runnable
或Callable
中,交由线程池来执行。
Spring的@Async异步
自定义异步线程池
*/**
\* 线程池参数配置,多个线程池实现线程池隔离,@Async注解,默认使用系统自定义线程池,可在项目中设置多个线程池,在异步调用的时候,指明需要调用的线程池名称,比如:@Async("taskName")
@EnableAsync
@Configuration
public class TaskPoolConfig {
/**
\* 自定义线程池
\*
**/*
@Bean("taskExecutor")
public Executor taskExecutor() {
*//返回可用处理器的Java虚拟机的数量 12*
int i = Runtime.getRuntime().availableProcessors();
System.out.println("系统最大线程数 : " + i);
ThreadPoolTaskExecutor executor = new ThreadPoolTaskExecutor();
*//核心线程池大小*
executor.setCorePoolSize(16);
*//最大线程数*
executor.setMaxPoolSize(20);
*//配置队列容量,默认值为Integer.MAX_VALUE*
executor.setQueueCapacity(99999);
*//活跃时间*
executor.setKeepAliveSeconds(60);
*//线程名字前缀*
executor.setThreadNamePrefix("asyncServiceExecutor -");
*//设置此执行程序应该在关闭时阻止的最大秒数,以便在容器的其余部分继续关闭之前等待剩余的任务完成他们的执行*
executor.setAwaitTerminationSeconds(60);
*//等待所有的任务结束后再关闭线程池*
executor.setWaitForTasksToCompleteOnShutdown(true);
return executor;
}
}
AsyncService
public interface AsyncService {
MessageResult sendSms(String callPrefix, String mobile, String actionType, String content);
MessageResult sendEmail(String email, String subject, String content);
}
@Slf4j
@Service
public class AsyncServiceImpl implements AsyncService {
@Autowired
private IMessageHandler mesageHandler;
@Override
@Async("taskExecutor")
public MessageResult sendSms(String callPrefix, String mobile, String actionType, String content) {
try {
Thread.sleep(1000);
mesageHandler.sendSms(callPrefix, mobile, actionType, content);
} catch (Exception e) {
log.error("发送短信异常 -> ", e)
}
}
@Override
@Async("taskExecutor")
public sendEmail(String email, String subject, String content) {
try {
Thread.sleep(1000);
mesageHandler.sendsendEmail(email, subject, content);
} catch (Exception e) {
log.error("发送email异常 -> ", e)
}
}
}
在实际项目中, 使用@Async
调用线程池,推荐等方式是是使用自定义线程池的模式,不推荐直接使用@Async直接实现异步。
Spring ApplicationEvent事件实现异步
定义事件
public class AsyncSendEmailEvent extends ApplicationEvent {
/**
* 邮箱
**/
private String email;
/**
* 主题
**/
private String subject;
/**
* 内容
**/
private String content;
/**
* 接收者
**/
private String targetUserId;
}
定义事件处理器
@Slf4j
@Component
public class AsyncSendEmailEventHandler implements ApplicationListener<AsyncSendEmailEvent> {
@Autowired
private IMessageHandler mesageHandler;
@Async("taskExecutor")
@Override
public void onApplicationEvent(AsyncSendEmailEvent event) {
if (event == null) {
return;
}
String email = event.getEmail();
String subject = event.getSubject();
String content = event.getContent();
String targetUserId = event.getTargetUserId();
mesageHandler.sendsendEmailSms(email, subject, content, targerUserId);
}
}
另外,可能有些时候采用ApplicationEvent实现异步的使用,当程序出现异常错误的时候,需要考虑补偿机制,那么这时候可以结合Spring Retry重试来帮助我们避免这种异常造成数据不一致问题。
ThreadUtil异步工具类(比较常用)
@Slf4j
public class ThreadUtils {
public static void main(String[] args) {
for (int i = 0; i < 3; i++) {
ThreadUtil.execAsync(() -> {
ThreadLocalRandom threadLocalRandom = ThreadLocalRandom.current();
int number = threadLocalRandom.nextInt(20) + 1;
System.out.println(number);
});
log.info("当前第:" + i + "个线程");
}
log.info("task finish!");
}
}
【推荐】编程新体验,更懂你的AI,立即体验豆包MarsCode编程助手
【推荐】凌霞软件回馈社区,博客园 & 1Panel & Halo 联合会员上线
【推荐】抖音旗下AI助手豆包,你的智能百科全书,全免费不限次数
【推荐】博客园社区专享云产品让利特惠,阿里云新客6.5折上折
【推荐】轻量又高性能的 SSH 工具 IShell:AI 加持,快人一步
· DeepSeek “源神”启动!「GitHub 热点速览」
· 微软正式发布.NET 10 Preview 1:开启下一代开发框架新篇章
· C# 集成 DeepSeek 模型实现 AI 私有化(本地部署与 API 调用教程)
· DeepSeek R1 简明指南:架构、训练、本地部署及硬件要求
· 2 本地部署DeepSeek模型构建本地知识库+联网搜索详细步骤