网易首页 > 网易号 > 正文 申请入驻

【177期】Spring 体系中,千万不要这样使用 @Async 注解!

0
分享至

点击上方“Java精选”,选择“设为星标”

别问别人为什么,多问自己凭什么!

下方有惊喜,留言必回,有问必答!

每天08:35更新文章,每天进步一点点...

在实际的项目中,对于一些用时比较长的代码片段或者函数,我们可以采用异步的方式来执行,这样就不会影响整体的流程了。比如我在一个用户请求中需要上传一些文件,但是上传文件的耗时会相对来说比较长,这个时候如果上传文件的成功与否不影响主流程的话,就可以把上传文件的操作异步化,在spring boot中比较常见的方式就是把要异步执行的代码片段封装成一个函数,然后在函数头使用@Async注解,就可以实现代码的异步执行(当然首先得在启动类上加上@EnableAsync注解了)。

具体的使用方式这里我也就不再演示了,网上教大家使用@Async的很多。今天我要讲的并不是怎么去使用@Async注解,而是讲我在实际开发过程中遇到的一个坑,希望你不要再犯。

首先,再明确一点,学习一个知识,第一步是找到相应的官网或是比较权威的网站。

那么这个坑是什么呢?就是如果你在同一个类里面调用一个自己的被@Async修饰的函数时,这个函数将不会被异步执行,它依然是同步执行的!所以你如果没有经过测试就想当然的以为只要在方法头加上@Async就能达到异步的效果,那么你很有可能会得到相反的效果。这个是很要命的。

所以我来给你们演示一下,这个效果是多么恐怖。为什么说它恐怖,是因为在程序员的眼中,一切不符合期望的行为都是bug,bug能不恐怖吗?

首先我们先看一个正确使用的方式,建一个spring boot项目,如果你是用Intellij IDEA新建的项目,记得勾上web的依赖。

项目建好后,我们在启动类上加上@EnableAsync注解:

import org.springframework.boot.SpringApplication;
import org.springframework.boot.autoconfigure.SpringBootApplication;
import org.springframework.scheduling.annotation.EnableAsync;

@SpringBootApplication
@EnableAsync
public class AsyncdemoApplication {

public static void main(String[] args) {
SpringApplication.run(AsyncdemoApplication.class, args);
}

}

然后再新建一个类Task,用来放三个异步任务doTaskOne、doTaskTwo、doTaskThree:

import org.springframework.scheduling.annotation.Async;
import org.springframework.stereotype.Component;

import java.util.Random;

/**
* @author https://www.chuckfang.top
* @date Created on 2019/11/12 11:34
*/
@Component
public class Task {

public static Random random = new Random();

@Async
public void doTaskOne() throws Exception {
System.out.println("开始做任务一");
long start = System.currentTimeMillis();
Thread.sleep(random.nextInt(10000));
long end = System.currentTimeMillis();
System.out.println("完成任务一,耗时:" + (end - start) + "毫秒");
}

@Async
public void doTaskTwo() throws Exception {
System.out.println("开始做任务二");
long start = System.currentTimeMillis();
Thread.sleep(random.nextInt(10000));
long end = System.currentTimeMillis();
System.out.println("完成任务二,耗时:" + (end - start) + "毫秒");
}

@Async
public void doTaskThree() throws Exception {
System.out.println("开始做任务三");
long start = System.currentTimeMillis();
Thread.sleep(random.nextInt(10000));
long end = System.currentTimeMillis();
System.out.println("完成任务三,耗时:" + (end - start) + "毫秒");
}
}

在单元测试类上注入Task,在测试用例上测试这三个方法的执行过程:

@SpringBootTest
class AsyncdemoApplicationTests {

public static Random random = new Random();

@Autowired
Task task;

@Test
void contextLoads() throws Exception {
task.doTaskOne();
task.doTaskTwo();
task.doTaskThree();
Thread.sleep(10000);
}
}

我们启动看看效果:

我们看到三个任务确实是异步执行的,那我们再看看错误的使用方法。

我们在测试类里面把这三个函数再写一遍,并在测试用例上调用测试类自己的方法:

@SpringBootTest
class AsyncdemoApplicationTests {

public static Random random = new Random();

@Test
void contextLoads() throws Exception {
doTaskOne();
doTaskTwo();
doTaskThree();
Thread.sleep(10000);
}

@Async
public void doTaskOne() throws Exception {
System.out.println("开始做任务一");
long start = System.currentTimeMillis();
Thread.sleep(random.nextInt(10000));
long end = System.currentTimeMillis();
System.out.println("完成任务一,耗时:" + (end - start) + "毫秒");
}

@Async
public void doTaskTwo() throws Exception {
System.out.println("开始做任务二");
long start = System.currentTimeMillis();
Thread.sleep(random.nextInt(10000));
long end = System.currentTimeMillis();
System.out.println("完成任务二,耗时:" + (end - start) + "毫秒");
}

@Async
public void doTaskThree() throws Exception {
System.out.println("开始做任务三");
long start = System.currentTimeMillis();
Thread.sleep(random.nextInt(10000));
long end = System.currentTimeMillis();
System.out.println("完成任务三,耗时:" + (end - start) + "毫秒");
}
}

我们再看看效果:

它们竟然是顺序执行的!也就是同步执行,并没有达到异步的效果,这要是在生产上使用,岂不凉凉。

这种问题如果不进行测试还是比较难发现的,特别是你想要异步执行的代码并不会执行太久,也就是同步执行你也察觉不出来,或者说你根本发现不了它是不是异步执行。这种错误也很容易犯,特别是当你把一个类里面的方法提出来想要异步执行的时候,你并不会想着新建一个类来放这个方法,而是会在当前类上直接抽取为一个方法,然后在方法头上加上@Async注解,你以为这样就完事了,其实并没有起到异步的作用!我也是在改进我们项目的文件上传时才发现这个问题的。因为文件上传也不会花费太久,所以真的很隐蔽。

其实@Async的这个性质在官网上已经有过说明了,官网:是这样说的:

文章在一开始就提到了@Async的两个限制,其中第二个就是调用自己类上的异步方法是不起作用的。下面也讲了原因,就是这种使用方式绕过了代理而直接调用了方法,所以肯定是同步的了。从这里,我们也知道了另外一个知识点,就是@Async注解其实是通过代理的方式来实现异步调用的。

上面这个错误使用方法,我目前没有在网上看到过有人说明。希望你看完我的博客之后不要再犯同样的错误了,或者你赶快检查一下你自己的项目中有没有这样使用@Async注解的。如果觉得文章不错,可以推荐给同事看哦,提醒他们正确使用@Async。

作者:方程的博客 https://chuckfang.com/2019/11/13/Async/

公众号“Java精选”所发表内容注明来源的,版权归原出处所有(无法查证版权的或者未注明出处的均来自网络,系转载,转载的目的在于传递更多信息,版权属于原作者。如有侵权,请联系,笔者会第一时间删除处理!

------ THE END ------

精品资料,超赞福利!


3000+ 道面试题在线刷,最新、最全 Java 面试题!

期往精选 点击标题可跳转

技术交流群!

最近有很多人问,有没有读者&异性交流群,你懂的!想知道如何加入。加入方式很简单,有兴趣的同学,只需要点击下方卡片,回复“加群”,即可免费加入交流群!

文章有帮助的话,在看,转发吧!

特别声明:以上内容(如有图片或视频亦包括在内)为自媒体平台“网易号”用户上传并发布,本平台仅提供信息存储服务。

Notice: The content above (including the pictures and videos if any) is uploaded and posted by a user of NetEase Hao, which is a social media platform and only provides information storage services.

相关推荐
热点推荐
董明珠再现惊人言论,冲上热搜第一!

董明珠再现惊人言论,冲上热搜第一!

大佬灼见
2026-07-03 14:13:41
盐城作废一批居留许可,这群反向润中国的人,终于踢到铁板了!

盐城作废一批居留许可,这群反向润中国的人,终于踢到铁板了!

李砍柴
2026-07-03 14:15:08
俄总统新闻秘书:普京宣布俄军“完全解放”卢甘斯克

俄总统新闻秘书:普京宣布俄军“完全解放”卢甘斯克

澎湃新闻
2026-07-04 05:14:03
世界杯险峰对决!阿根廷加时3-2绝杀佛得角,黑马神话悲壮落幕

世界杯险峰对决!阿根廷加时3-2绝杀佛得角,黑马神话悲壮落幕

海右那人
2026-07-04 08:51:35
莫迪喊高市早苗"妹妹",高市笑着回应:你叫我漂亮妹妹,网友:幼稚!国际交往不是过家家

莫迪喊高市早苗"妹妹",高市笑着回应:你叫我漂亮妹妹,网友:幼稚!国际交往不是过家家

每日经济新闻
2026-07-03 19:44:59
炎炎夏日兰姐带玥儿逛街,洋洋总携女同游三里屯

炎炎夏日兰姐带玥儿逛街,洋洋总携女同游三里屯

奇怪的鲨鱼们
2026-07-04 03:06:41
中国摩托车在非洲的真实现状:被印度摩托车打得完全没有招架之力

中国摩托车在非洲的真实现状:被印度摩托车打得完全没有招架之力

抽象派大师
2026-07-04 00:42:49
NBA两笔重磅交易完成!湖人1换3放弃状元,首发阵容彻底解散

NBA两笔重磅交易完成!湖人1换3放弃状元,首发阵容彻底解散

锐评利物浦
2026-07-04 09:45:10
中超第17轮,青岛海牛-成都蓉城,前瞻:此消彼长

中超第17轮,青岛海牛-成都蓉城,前瞻:此消彼长

足坛超短波
2026-07-04 08:20:15
47岁裁判马宁哭了:被断定世界杯结束,他把不可能变可能

47岁裁判马宁哭了:被断定世界杯结束,他把不可能变可能

风信子的花
2026-07-03 20:02:10
哈梅内伊棺前摆着遇害外孙女的遗照,其女儿、女婿、儿媳及14个月大的外孙女均在美以大规模空袭中遇害;伊朗首都空域6日将全面关闭

哈梅内伊棺前摆着遇害外孙女的遗照,其女儿、女婿、儿媳及14个月大的外孙女均在美以大规模空袭中遇害;伊朗首都空域6日将全面关闭

政知新媒体
2026-07-03 19:36:56
为什么俄罗斯宁愿死磕欧洲,也不愿发展资源丰富的远东地区?

为什么俄罗斯宁愿死磕欧洲,也不愿发展资源丰富的远东地区?

解锁世界风云
2026-07-04 08:23:24
有没有手撕绿茶的超爽经历?网友:我必须给她上一课

有没有手撕绿茶的超爽经历?网友:我必须给她上一课

另子维爱读史
2026-07-02 21:02:00
艾顿1换3交易达成!湖人一举多得评级为B 奇才明显不合理仅评C

艾顿1换3交易达成!湖人一举多得评级为B 奇才明显不合理仅评C

罗说NBA
2026-07-04 05:08:22
演唱会刚结束,任素汐体面形象遭撕碎,私生活混乱演技再好也没用

演唱会刚结束,任素汐体面形象遭撕碎,私生活混乱演技再好也没用

秋姐居
2026-07-03 19:18:29
唯一在世的中共一代领导人,曾任周总理秘书,晚年坚持做公益

唯一在世的中共一代领导人,曾任周总理秘书,晚年坚持做公益

史不语
2026-07-02 06:00:03
曼联官宣奥纳纳离队,谈判免费签一人替代!续约户口本继续做陪练

曼联官宣奥纳纳离队,谈判免费签一人替代!续约户口本继续做陪练

罗米的曼联博客
2026-07-04 08:13:58
法拉第未来厂房人去楼空,贾跃亭炸上热搜!

法拉第未来厂房人去楼空,贾跃亭炸上热搜!

财经三分钟pro
2026-07-03 15:28:40
“父爱真没有母爱纯粹!”孩子报班事件,掀开多少爸爸的金钱观念

“父爱真没有母爱纯粹!”孩子报班事件,掀开多少爸爸的金钱观念

熙熙说教
2026-07-03 19:29:27
阿拉巴:我还没考虑过未来;完美状态才能击败阿根廷和西班牙

阿拉巴:我还没考虑过未来;完美状态才能击败阿根廷和西班牙

懂球帝
2026-07-03 19:11:21
2026-07-04 10:00:49
Java精选
Java精选
一场永远也演不完的戏
1796文章数 3859关注度
往期回顾 全部

科技要闻

iPhone 18 Pro泄密影响恶劣,印度调查塔塔

头条要闻

阿根廷加时赛3-2绝杀佛得角 世界杯最大黑马昂首出局

头条要闻

阿根廷加时赛3-2绝杀佛得角 世界杯最大黑马昂首出局

体育要闻

今夏最动人告别!世界从此记住佛得角

娱乐要闻

海来阿木孕期出轨指控掀起全网热议

财经要闻

韩国股市杠杆失控:450亿美元资金狂飙

汽车要闻

方程豹钛9内饰曝光 用上了长联屏设计/下半年上市

态度原创

艺术
教育
游戏
房产
军事航空

艺术要闻

这位女子,在画坛默默无闻,作品清新质朴

教育要闻

孩子的10种暑假状态,这不就是我家的现状么

魔兽世界:时光服玩家吵翻天,鸟德改动实装,到底有哪些变化?

房产要闻

总裁空缺17个月、现金缺口超1000亿:金融局“局外人”入局万科

军事要闻

俄大使馆遇袭 2年多遭袭击次数已超25次

无障碍浏览 进入关怀版