异步和多线程区别
同步、异步、多线程、阻塞、非阻塞
同步(sync)-同步阻塞
发出一个功能调用时,在没有得到结果之前,该调用就不返回。
1 | public class Test { |
执行结果
1 | 处理前执行... |
异步(async)-异步非阻塞
与同步相对,在调用发出之后就直接返回了,可能没有返回结果。对于异步调用,调用的返回并不受调用者控制。
当调用完成后,一般通过状态、通知或回调来通知调用者,具体如下:
状态:调用者监听被调用者的状态(轮询),需要每隔一定时间检查一次,效率低。
通知:当被调用者执行完成后,向调用者发出通知,无需消耗太多性能。
回调:与通知类似,当被调用者执行完成后,调用调用者提供的回调函数。
下面代码若不调用 task.get()
就是多线程。
1 | public class Test { |
执行结果
1 | 处理前执行... |
多线程
1 | public class Test { |
执行结果
1 | 处理前执行... |
多线程和异步区别
多线程关注功能的并发执行,与具体的执行者相关。
异步编程关注函数之间的非阻塞执行,与任务相关,我们可以将异步应用于单线程或多线程当中。
异步和多线程并不是一个同等关系,异步是最终目的,多线程只是实现异步的一种手段。
实现异步场景(非多线程)
手机验证码登录场景,当我们点击 发送验证码
时,页面立即提示发送成功。
实现:
1、接口收到请求后,生成一个六位验证码,将 发送验证码
的任务放到 验证码队列
(生产者),返回接口 发送成功
。
2、验证码消费者负责具体发送功能,同时将此验证码存到redis中的Hash表(key为固定值 SMS_verification_code
,field为 手机号
,value为 验证码+生成时间
)。
3、当用户输入验证码登录调用登录接口时,查询redis中key为固定值 SMS_verification_code
,field为 手机号
的value值,有几种情况:
value值 | 验证value有效期(5分钟) | value与用户输入值比较 | 处理 |
---|---|---|---|
不存在 | —— | —— | 登录接口返回 msg=”验证码错误” |
存在 | 无效 | —— | 登录接口返回 msg=”验证码过期,请重新获取!” |
存在 | 有效 | 不一致 | 登录接口返回 msg=”验证码错误” |
存在 | 有效 | 一致 | 继续登录验证操作 |
阻塞(block)
阻塞调用:指调用结果返回(或调用者收到通知)之前,当前线程会被挂起,即不继续执行后续操作。
简单来说,等前一件做完了才能做下一件事。
非阻塞(non-block)
非阻塞调用:指在不能立刻得到调用结果的情况下,该调用不会阻塞当前线程。
总结
所以所谓同步异步,是对于被调用者而言的;而阻塞非阻塞,则是对调用者而言的。
加深理解:
1、同步阻塞:你打电话给114查路线,在不挂断的情况下,客服帮你查了十分钟之后告诉你,期间你一直在接听电话。
2、同步非阻塞:你打电话给114查路线,在不挂断的情况下,客服帮你查了十分钟之后告诉你,你期间吃了个🍉(打电话没有影响你做其他事)。
3、异步非阻塞:你打电话给114查路线,客服说查好之后打给你,这期间你可以做任何事。
4、异步阻塞:你打电话给114查路线,客服说查好之后打给你,但这期间你什么都没做,等到回复电话之后,再继续下一步动作。(是不是很傻)现实运用中,多线程获取锁就是异步阻塞。