1 线程同步和异步
线程同步:A线程要请求某个资源,但是此资源正在被B线程使用中,因为同步机制存在,A只能等待下去。耗时较长,安全性较高。
线程异步:A线程要请求某个资源,但是此资源正在被B线程使用中,因为没有同步机制存在,A线程仍然请求的到。
一个进程启动的多个不相干的进程,他们之间的相互关系为异步;同步必须执行到底后才能执行其他操作,异步可同时执行。
多个线程执行的时候需要同步,如果是单线程则不需要同步。
2 异步实例
主方法和被调用的方法必须是不同的类,才能实现多线程。
2.1 启动类
使用@EnableAsync来开启 SpringBoot 对于异步任务的支持。
Application:
@SpringBootApplication
@EnableAsync
public class Application {
public static void main(String[] args) {
SpringApplication.run(Application.class, args);
}
}
2.2多线程配置类:
// ThredPoolTaskExcutor的处理流程
// 当池子大小小于corePoolSize,就新建线程,并处理请求
// 当池子大小等于corePoolSize,把请求放入workQueue中,池子里的空闲线程就去workQueue中取任务并处理
// 当workQueue放不下任务时,就新建线程入池,并处理请求,如果池子大小撑到了maximumPoolSize,就用RejectedExecutionHandler来做拒绝处理
// 当池子的线程数大于corePoolSize时,多余的线程会等待keepAliveTime长时间,如果无请求可处理就自行销毁
@Override
@Bean
public Executor getAsyncExecutor() {
ThreadPoolTaskExecutor executor = new ThreadPoolTaskExecutor();
// 核心线程数:线程池创建的时候初始化的线程数
executor.setCorePoolSize(10);
// 最大线程数:线程池最大的线程数,只有缓冲队列满了之后才会申请超过核心线程数的线程
executor.setMaxPoolSize(100);
// 缓冲队列:用来缓冲执行任务的队列
executor.setQueueCapacity(50);
// 线程池关闭:等待所有任务都完成再关闭
executor.setWaitForTasksToCompleteOnShutdown(true);
// 等待时间:等待5秒后强制停止
executor.setAwaitTerminationSeconds(5);
// 允许空闲时间:超过核心线程之外的线程到达60秒后会被销毁
executor.setKeepAliveSeconds(60);
// 线程名称前缀
executor.setThreadNamePrefix("Credit-Async-");
// 初始化线程
executor.initialize();
return executor;
}
// 异常处理器
@Override
public AsyncUncaughtExceptionHandler getAsyncUncaughtExceptionHandler() {
return (ex, method, params) -> {
logger.error("=========================="+ex.getMessage()+"=======================", ex);
logger.error("exception method:"+method.getName());
};
}
这样我们可在代码中通过@Async注释来调用线程池。
注:
在本人使用使用@Async注释时,会出现没有生效的情况,其中主要是因为aop代理的缘故,被调用方法 和 调用处的代码都处在同一个类,所以只是相当于本类调用,并没有使用代理类 从而@Async并没有产生效果。
附:常用失效原因
1.@SpringBootApplication启动类当中没有添加@EnableAsync注解。
2.异步方法使用注解@Async的返回值只能为void或者Future。
3.没有走Spring的代理类。因为@Transactional和@Async注解的实现都是基于Spring的AOP,而AOP的实现是基于动态代理模式实现的。那么注解失效的原因就很明显了,有可能因为调用方法的是对象本身而不是代理对象,因为没有经过Spring容器管理。