本文将会从java实现异步的方式出发,到spring对异步的支持,再到spring中异步的实现,希望通过本文章能把异步的基本部分讲透彻。
异步
提到异步,肯定要提到同步的概念,那么我们就对比着来理解这两个概念。其实我们写的大部分程序都是同步执行的。对于同步,最简单的理解方式就是当一行代码执行完后才能执行下面的一行代码。同理,异步就是两行代码可以同时执行,我们知道cpu是可以同时执行多个任务的,不管是通过多核还是多线程都可以实现,操作系统层面给我们提供了进程和线程相关的系统调用,使得我们可以把两个任务交给cpu执行。那么在编程语言层面如何才能实现异步执行呢?在java中也是提供了线程相关的api,我们可以通过对线程api的调用,实现异步。
java阶段的异步
多线程
public class asyncForJava {
public static void main(String[] args) {
new Thread(()-> System.out.println("hello world !"));
print();
new Thread(()-> get("aaa"));
}
public static void print(){
System.out.println("a");
}
public static String get(String s) {
return "hello" + s;
}
}
这样就可以实现异步执行语句以及异步执行方法,看似解决了方法的异步调用,但是这样是没法完成返回值回传
于是java引入了Callable接口
public static void main(String[] args) throws ExecutionException, InterruptedException {
new Thread(()-> System.out.println("hello world !"));
print();
new Thread(()-> get("aaa"));
FutureTask<Integer> futureTask = new FutureTask(()-> 1);
new Thread(futureTask,"futureTask").start();
Integer result = futureTask.get();
System.out.println(result);
}
这样就能实现异步执行后返回值的回传了
这里需要注意,使用get方法获取返回值,这个操作是阻塞的,至于阻塞是什么,这里不再详细解释,只需要知道程序执行到这里get到值就会往下面执行,get不到就会等待,一直到get到为止
线程池
为了方便对线程的管理,节约线程创建和销毁的成本,引入了池化技术
// 自定义Callable
class Task implements Callable<Integer>{
public static void main(String args[]){
// 使用
ExecutorService executor = Executors.newCachedThreadPool();
Future<Integer> result = executor.submit(()-> 1);
// 注意调用get方法会阻塞当前线程,直到得到结果。
// 所以实际编码中建议使用可以设置超时时间的重载get方法。
System.out.println(result.get());
}
}
以上就是java中关于异步的使用,所以java中的异步是通过多线程实现的
spring对异步的支持
spring封装了异步的使用步骤,通过简单的几步就可以实现方法的异步调用,主要步骤如下
1、@EnableAsync // 开启异步注解的支持
2、在异步方法上加入@Async 注解
3、如果方法有返回值,需要使用Future包装
下面是个简单的例子
@Component
@Component
@EnableAsync
public class AsyncForSpring {
@Async
public Object asyncHello() {
System.out.println("当前线程:" + Thread.currentThread().getName());
return "service hello";
}
public Object syncHello() {
System.out.println("当前线程:" + Thread.currentThread().getName());
return "service hello";
}
}
public class TestAsync {
public static void main(String[] args) {
AnnotationConfigApplicationContext ac = new AnnotationConfigApplicationContext();
ac.register(AsyncForSpring.class);
ac.refresh();
AsyncForSpring bean = ac.getBean(AsyncForSpring.class);
bean.syncHello();
bean.syncHello();
bean.syncHello();
bean.asyncHello();
bean.asyncHello();
bean.asyncHello();
bean.asyncHello();
}
}
执行结果如下
spring异步的实现原理
spring中异步的实现其实跟前面分析到的aop、事务的实现相似,所以我们还是从@EnableAsync注解开始分析,这也是一个组合注解
默认会执行PROXY
父类
可以看出mode是在注解中的属性配置的
上述流程往spring中注入了一个AsyncAnnotationBeanPostProcessor
先看一下这个类的继承关系
先看一下这个类
创建了一个AsyncAnnotationAdvisor
再看一下 AbstractAdvisingBeanPostProcessor
public Object postProcessAfterInitialization(Object bean, String beanName) {
if (this.advisor == null || bean instanceof AopInfrastructureBean) {
// Ignore AOP infrastructure such as scoped proxies.
return bean;
}
if (bean instanceof Advised) {
Advised advised = (Advised) bean;
if (!advised.isFrozen() && isEligible(AopUtils.getTargetClass(bean))) {
// Add our local Advisor to the existing proxy's Advisor chain...
if (this.beforeExistingAdvisors) {
advised.addAdvisor(0, this.advisor);
}
else {
advised.addAdvisor(this.advisor);
}
return bean;
}
}
if (isEligible(bean, beanName)) {
ProxyFactory proxyFactory = prepareProxyFactory(bean, beanName);
if (!proxyFactory.isProxyTargetClass()) {
evaluateProxyInterfaces(bean.getClass(), proxyFactory);
}
proxyFactory.addAdvisor(this.advisor);
customizeProxyFactory(proxyFactory);
return proxyFactory.getProxy(getProxyClassLoader());
}
// No proxy needed.
return bean;
}
这里会完成对异步类的代理