其他
【166期】面试官问:为什么不建议使用 @Async 注解?
点击上方“Java精选”,选择“设为星标”
别问别人为什么,多问自己凭什么!
下方留言必回,有问必答!
每天 08:35 更新文章,每天进步一点点...
对于异步方法调用,从Spring3开始提供了@Async注解,该注解可以被标在方法上,以便异步地调用该方法。调用者将在调用时立即返回,方法的实际执行将提交给Spring TaskExecutor的任务中,由指定的线程池中的线程执行。
在项目应用中,@Async调用线程池,推荐使用自定义线程池的模式。自定义线程池常用方案:重新实现接口AsyncConfigurer。
#应用场景
同步:同步就是整个处理过程顺序执行,当各个过程都执行完毕,并返回结果。
异步:异步调用则是只是发送了调用的指令,调用者无需等待被调用的方法完全执行完毕;而是继续执行下面的流程。例如, 在某个调用中,需要顺序调用 A, B, C三个过程方法;如他们都是同步调用,则需要将他们都顺序执行完毕之后,方算作过程执行完毕;如B为一个异步的调用方法,则在执行完A之后,调用B,并不等待B完成,而是执行开始调用C,待C执行完毕之后,就意味着这个过程执行完毕了。在Java中,一般在处理类似的场景之时,都是基于创建独立的线程去完成相应的异步调用逻辑,通过主线程和不同的业务子线程之间的执行流程,从而在启动独立的线程之后,主线程继续执行而不会产生停滞等待的情况。
#Spring 已经实现的线程池
SimpleAsyncTaskExecutor:不是真的线程池,这个类不重用线程,默认每次调用都会创建一个新的线程。 SyncTaskExecutor:这个类没有实现异步调用,只是一个同步操作。只适用于不需要多线程的地方。 ConcurrentTaskExecutor:Executor的适配类,不推荐使用。如果ThreadPoolTaskExecutor不满足要求时,才用考虑使用这个类。 SimpleThreadPoolTaskExecutor:是Quartz的SimpleThreadPool的类。线程池同时被quartz和非quartz使用,才需要使用此类。 ThreadPoolTaskExecutor :最常使用,推荐。其实质是对java.util.concurrent.ThreadPoolExecutor的包装。
最简单的异步调用,返回值为void 带参数的异步调用,异步方法可以传入参数 存在返回值,常调用返回Future
无返回值调用
有返回值Future调用
有返回值CompletableFuture调用
CompletionStage代表异步计算过程中的某一个阶段,一个阶段完成以后可能会触发另外一个阶段 一个阶段的计算执行可以是一个Function,Consumer或者Runnable。比如:
stage.thenApply(x -> square(x)).thenAccept(x -> System.out.print(x)).thenRun(() -> System.out.println())
一个阶段的执行可能是被单个阶段的完成触发,也可能是由多个阶段一起触发
它可能代表一个明确完成的Future,也有可能代表一个完成阶段( CompletionStage ),它支持在计算完成以后触发一些函数或执行某些动作。 它实现了Future和CompletionStage接口
默认线程池的弊端
newFixedThreadPool和newSingleThreadExecutor:主要问题是堆积的请求处理队列可能会耗费非常大的内存,甚至OOM。 newCachedThreadPool和newScheduledThreadPool:要问题是线程数最大数是Integer.MAX_VALUE,可能会创建数量非常多的线程,甚至OOM。
#@Async应用自定义线程池
重新实现接口AsyncConfigurer 继承AsyncConfigurerSupport 配置由自定义的TaskExecutor替代内置的任务执行器
实现接口AsyncConfigurer
继承AsyncConfigurerSupport
配置自定义的TaskExecutor
Executor.class:ThreadPoolExecutorAdapter->ThreadPoolExecutor->AbstractExecutorService->ExecutorService->Executor
TaskExecutor.class:ThreadPoolTaskExecutor->SchedulingTaskExecutor->AsyncTaskExecutor->TaskExecutor
来源:码农架构
3000+ 道面试题在线刷,最新、最全 Java 面试题!
【158期】Spring Boot + Redis 分布式锁:模拟 10万人的秒杀抢单
【159期】面试官问:说说 MongoDB 批量操作与 MySQL 效率对比?
【160期】实习面试:为什么 Java 中 1000==1000 为 false,而 100==100 为 true?
【161期】MySQL 性能优化的 9 种姿势,面试再也不怕了!
【162期】面试官:请说说对 HashMap 及 LinkedHashMap 源码底层的深入理解(八股文)
【163期】MYSQL 中 SQL 语句三种去除重复数据的方法
最近有很多人问,有没有读者交流群,想知道如何加入。加入方式很简单,有兴趣的同学,只需要点击下方卡片,回复“加群”,即可免费加入我们的高质量技术交流群!