Java开启异步线程的几种方法
开启异步线程方法
整体描述
在java中异步线程很重要,比如在业务流处理时,需要通知硬件设备,发短信通知用户,或者需要上传一些图片资源到其他服务器这种耗时的操作,在主线程里处理会阻塞整理流程,而且我们也不需要等待处理结果之后再进行下一步操作,这时候就可以使用异步线程进行处理,这样主线程不会因为这些耗时的操作而阻塞,保证主线程的流程可以正常进行。
最近在项目中使用了很多线程的操作,在这做个记录。
实现方法
线程的操作,是java中最重要的部分之一,实现线程操作也有很多种方法,这里仅介绍几种常用的。在springboot框架中,可以使用注解简单实现线程的操作,还有AsyncManager的方式,如果需要复杂的线程操作,可以使用线程池实现。下面根据具体方法进行介绍。
一、注解@Async(常用)
springboot框架的注解,使用时也有一些限制,这个在网上也有很多介绍,@Async注解不能在类本身直接调用,在springboot框架中,把这个注解加入到一个bean对象的方法中,即可实现异步操作:
1.1 线程池配置类
在springboot的config中添加 @EnableAsync注解,开启异步线程功能
将配置类放入容器中,并指定名称
import lombok.extern.slf4j.Slf4j;
import org.springframework.aop.interceptor.AsyncUncaughtExceptionHandler;
import org.springframework.context.annotation.Bean;
import org.springframework.context.annotation.Configuration;
import org.springframework.scheduling.annotation.AsyncConfigurer;
import org.springframework.scheduling.annotation.EnableAsync;
import org.springframework.scheduling.concurrent.ThreadPoolTaskExecutor;import java.util.concurrent.Executor;
import java.util.concurrent.ThreadPoolExecutor;/* 异步——线程池配置 @author xuzhuh* @date 2023.03.22*/
@Slf4j
@Configuration
@EnableAsync
public class AsyncConfiguration implements AsyncConfigurer {@Bean(name = "asyncPoolTaskExecutor")public ThreadPoolTaskExecutor executor() {ThreadPoolTaskExecutor taskExecutor = new ThreadPoolTaskExecutor();//核心线程数taskExecutor.setCorePoolSize(2);//线程池维护线程的最大数量,只有在缓冲队列满了之后才会申请超过核心线程数的线程taskExecutor.setMaxPoolSize(10);//缓存队列taskExecutor.setQueueCapacity(200);//设置线程的空闲时间,当超过了核心线程出之外的线程在空闲时间到达之后会被销毁taskExecutor.setKeepAliveSeconds(200);//异步方法内部线程名称taskExecutor.setThreadNamePrefix("async-log-");/* 当线程池的任务缓存队列已满并且线程池中的线程数目达到maximumPoolSize,如果还有任务到来就会采取任务拒绝策略* 通常有以下四种策略:* ThreadPoolExecutor.AbortPolicy:丢弃任务并抛出RejectedExecutionException异常。* ThreadPoolExecutor.DiscardPolicy:也是丢弃任务,但是不抛出异常。* ThreadPoolExecutor.DiscardOldestPolicy:丢弃队列最前面的任务,然后重新尝试执行任务(重复此过程)* ThreadPoolExecutor.CallerRunsPolicy:重试添加当前的任务,自动重复调用 execute() 方法,直到成功*/taskExecutor.setRejectedExecutionHandler(new ThreadPoolExecutor.CallerRunsPolicy());taskExecutor.setTaskDecorator(new ThreadCtxCopyDecorator());taskExecutor.initialize();return taskExecutor;}/* 指定默认线程池* The {@link Executor} instance to be used when processing async method invocations.*/@Overridepublic Executor getAsyncExecutor() {return executor();}/* The {@link AsyncUncaughtExceptionHandler} instance to be used* when an exception is thrown during an asynchronous method execution* with {@code void} return type.*/@Overridepublic AsyncUncaughtExceptionHandler getAsyncUncaughtExceptionHandler() {return (ex, method, params) -> log.error("线程池执行任务发送未知错误, 执行方法:{}", method.getName(), ex);}
}
1.2 使用注解
在需要异步的方法上 加上注解
注意:这个使用这个注解的时候也必须是一个bean对象
/* 邮件收发api @author xuzhuh*/
@Service
public interface IMsgApiService {/* 发送邮件 @param param* @return*/@PostMapping("/msgSend/feignClientSend")@Async("asyncPoolTaskExecutor")Res< String > send(FeignClientMsgParam param);@PostMapping("/msgSend/feignClientSendBatch")Res< String > sendBatch(List< FeignClientMsgParam > params);
}
二、AsyncManager
2.1 创建AsyncManager类
使用AsyncManager首先需要创建一个AsyncManager类,这个在springboot框架中应该也是有的:
/* 异步任务管理器 @author thcb*/
public class AsyncManager {/* 操作延迟10毫秒*/private final int OPERATE_DELAY_TIME = 10;/* 异步操作任务调度线程池*/private ScheduledExecutorService executor = SpringUtils.getBean("scheduledExecutorService");/* 单例模式*/private AsyncManager() {}private static AsyncManager me = new AsyncManager();public static AsyncManager me() {return me;}/* 执行任务 @param task 任务*/public void execute(TimerTask task) {executor.schedule(task, OPERATE_DELAY_TIME, TimeUnit.MILLISECONDS);}/* 停止任务线程池*/public void shutdown() {Threads.shutdownAndAwaitTermination(executor);}
}
2.2 执行异步操作
使用AsyncManager执行异步操作也比较简单,直接调用即可:
// 异步线程池
AsyncManager.me().execute(sleepingTest());
三、线程池
略