1. 概述
本篇文章分享了应用层的异步是如何实现的,给出了java demo并用响应式编程方式进行了改写。
2. 异步说明
在开始前我们先明确下本篇文章所述异步的概念。
以下图中服务A发起对服务B的调用为例
同步时,一个调用需要消耗一个线程,服务A中Thread1线程调用服务B,等待服务B产生结果,并对结果进行处理。
异步时,Thread1可以复用,Thread1线程调用服务B后,不用等待服务B返回,它可以继续接收下一个请求,请求结果返回时,由另一个线程(也可能是Thread1)处理。
这样做有两个好处:
1. 线程复用,可以用少量线程处理大量请求。
2. 提高CPU的利用率,IO时CPU没有等待,而是在处理新的请求。
3. 异步的Java实现
同步就像打电话,A给B打电话时,B需要接电话,不然A一直等待。
异步就像发邮件,A给B发邮件时,B不需要在,B只需要把邮箱地址告诉A。
异步的实现也是依赖“邮箱地址”完成的,只是它有一个更正式的名字,叫回调地址。代码如下所示:
public class AsyncDemo {
//定义一个邮箱
private interface Callback{
void doOnError();
void doOnSuccess();
}
private static class A{
public void invokeB(String value) {
AsyncDemo.B b = new AsyncDemo.B();
//A发起对B的调用,并给B一个邮箱地址
b.doSomething(value, new AsyncDemo.Callback() {
@Override
public void doOnError() {
System.out.println("in class A method doOnError!");
}
@Override
public void doOnSuccess() {
System.out.println("in class A method doOnSuccess!");
}
});
}
}
private static class B{
public void doSomething(String value, AsyncDemo.Callback callback) {
//do something
try {
Thread.sleep(3000);
} catch (Exception e) {
e.printStackTrace();
}
//B处理完之后,回调地址
if(StringUtils.isEmpty(value)) {
callback.doOnError();
} else {
callback.doOnSuccess();
}
}
}
public static void main(String[] args) throws Exception{
A a = new A();
a.invokeB("sfsdf");
}
}
执行结果如下所示:
4. 响应式编程方式实现
什么是响应式编程,以及为什么要用响应式编程可以参考附录中的文章,本篇不在赘述。直接上代码。
public class AsyncWithReactor {
//此处定义一个邮箱
private interface Callback{
void doOnError();
void doOnSuccess();
}
private static class A{
public Mono invokeB(String value) {
B b = new B();
//调用B的返回结果通过Mono包装并返回
return Mono.create(sink -> {
//调用B时,传给B一个邮箱地址
b.doSomething(value, new Callback() {
@Override
public void doOnError() {
System.out.println("in class A method doOnError!");
sink.error(new Exception("doOnError"));
}
@Override
public void doOnSuccess() {
System.out.println("in class A method doOnSuccess!");
sink.success("doOnSuccess");
}
});
});
}
}
private static class B{
public void doSomething(String value, Callback callback) {
//do something
try {
Thread.sleep(3000);
} catch (Exception e) {
e.printStackTrace();
}
if(StringUtils.isEmpty(value)) {
callback.doOnError();
} else {
callback.doOnSuccess();
}
}
}
public static void main(String[] args) throws Exception{
A a = new A();
a.invokeB("aaaa").subscribe(result->{
System.out.println(result);
}, e->{
System.out.println(e);
});
}
}
执行结果如下所示:
5. 附录
6. 总结
本篇文章分享了应用层实现异步的方式、好处,给出了java demo并用响应式编程方式进行了改写,本篇文章分享的异步方式也可以用在rpc框架中。