java 异步并发

java 异步并发

   在Java中,如使用Tomcat,一个请求会分配一个线程进行请求处理,该线程负责获取数据、拼装数据或模板然后返回给前端;在同步调用获取数据接口的情况下(等待依赖系统返回数据),整个线程是一直被占用并阻塞的。如果有大量的这种请求,每个请求占用一个线程,但线程一直处于阻塞,降低了系统的吞吐量,这将导致应用的吞吐量下降;我们希望在调用依赖的服务响应比较慢,此时应该让出线程和CPU来处理下一个请求,当依赖的服务返回了再分配相应的线程来继续处理。而这应该有更好的解决方案:异步/协程。而Java是不支持协程的(虽然有些Java框架说支持,但还是高层API的封装),因此在Java中我们还可以使用异步来提升吞吐量。目前java一些开源框架(HttpClient\HttpAsyncClient、dubbo、thrift等等)大部分都支持。(开涛哥那本书上面介绍得)

几种调用方式

同步阻塞调用
即串行调用,响应时间为所有服务的响应时间总和;

半异步(异步Future)
线程池,异步Future,使用场景:并发请求多服务,总耗时为最长响应时间;提升总响应时间,但是阻塞主请求线程,高并发时依然会造成线程数过多,CPU上下文切换;

全异步(Callback)
Callback方式调用,使用场景:不考虑回调时间且只能对结果做简单处理,如果依赖服务是两个或两个以上服务,则不能合并两个服务的处理结果;不阻塞主请求线程,但使用场景有限。

异步回调链式编排
异步回调链式编排(JDK8 CompletableFuture),使用场景:其实不是异步调用方式,只是对依赖多服务的Callback调用结果处理做结果编排,来弥补Callback的不足,从而实现全异步链式调用。

同步阻塞调用

public class Test {

public static void main(String[] args) throws Exception {

   RpcService rpcService = new RpcService();

   HttpService httpService = new HttpService();

   //耗时10ms

   Map<String, String> result1 = rpcService.getRpcResult();

   //耗时20ms

   Integer result2 = httpService.getHttpResult();

   //总耗时30ms

}

static class RpcService {

   Map<String, String> getRpcResult() throws Exception {

       //调用远程方法(远程方法耗时约10ms,可以使用Thread.sleep模拟)

   }

}

static class HttpService {

   Integer getHttpResult() throws Exception {

       //调用远程方法(远程方法耗时约20ms,可以使用Thread.sleep模拟)

       Thread.sleep(20);

       return 0;

   }

}

}
半异步(异步Future)

public class Test {

final static ExecutorService executor = Executors.newFixedThreadPool(2);

public static void main(String[] args) {

   RpcService rpcService = new RpcService();

   HttpService httpService = new HttpService();

   Future<Map<String, String>> future1 = null;

   Future<Integer> future2 = null;

   try {

       future1 = executor.submit(() -> rpcService.getRpcResult());

       future2 = executor.submit(() -> httpService.getHttpResult());

       //耗时10ms

       Map<String, String> result1 = future1.get(300, TimeUnit.MILLISECONDS);

       //耗时20ms

       Integer result2 = future2.get(300, TimeUnit.MILLISECONDS);

       //总耗时20ms

   } catch (Exception e) {

       if (future1 != null) {

            future1.cancel(true);

       }

       if (future2 != null) {

            future2.cancel(true);

       }

       throw new RuntimeException(e);

   }

}

static class RpcService {

   Map<String, String> getRpcResult() throws Exception {

       //调用远程方法(远程方法耗时约10ms,可以使用Thread.sleep模拟)

   }

}

static class HttpService {

   Integer getHttpResult() throws Exception {

       //调用远程方法(远程方法耗时约20ms,可以使用Thread.sleep模拟)

   }

}

}

全异步(Callback)

public class AsyncTest {

public staticHttpAsyncClient httpAsyncClient;

public static CompletableFuture getHttpData(String url) {

   CompletableFuture asyncFuture = new CompletableFuture();

   HttpPost post = new HttpPost(url);

   HttpAsyncRequestProducer producer = HttpAsyncMethods.create(post);

   AsyncCharConsumer<HttpResponse> consumer = newAsyncCharConsumer<HttpResponse>() {

        HttpResponse response;

       protected HttpResponse buildResult(final HttpContext context) {

            return response;

       }

……

   };

   FutureCallback callback = new FutureCallback<HttpResponse>() {

       public void completed(HttpResponse response) {

           asyncFuture.complete(EntityUtils.toString(response.getEntity()));

       }

……

   };

   httpAsyncClient.execute(producer, consumer, callback);

   return asyncFuture;

}

public static void main(String[] args) throws Exception {

   AsyncTest.getHttpData("http://www.jd.com");

   Thread.sleep(1000000);

}

}
异步回调链式编排CompletableFuture
在这里插入图片描述
简单介绍
CompletableFuture
CompletableFuture类实现了CompletionStage和Future接口,所以你还是可以像以前一样通过阻塞或者轮询的方式获得结果,尽管这种方式不推荐使用。
CompletableFuture.completedFuture是一个静态辅助方法,用来返回一个已经计算好的CompletableFuture。
而以下四个静态方法用来为一段异步执行的代码创建CompletableFuture对象:
在这里插入图片描述
以Async结尾并且没有指定Executor的方法会使用ForkJoinPool.commonPool()作为它的线程池执行异步代码。

runAsync方法也好理解,它以Runnable函数式接口类型为参数,所以CompletableFuture的计算结果为空。

supplyAsync方法以Supplier函数式接口类型为参数,CompletableFuture的计算结果类型为U。

因为方法的参数类型都是函数式接口,所以可以使用lambda表达式实现异步任务,比如:
在这里插入图片描述
当CompletableFuture的计算结果完成,或者抛出异常的时候,我们可以执行特定的Action。主要是下面的方法
在这里插入图片描述
可以看到Action的类型是BiConsumer<? super T,? super Throwable>,它可以处理正常的计算结果,或者异常情况。
方法不以Async结尾,意味着Action使用相同的线程执行,而Async可能会使用其它的线程去执行(如果使用相同的线程池,也可能会被同一个线程选中执行)。

注意这几个方法都会返回CompletableFuture,当Action执行完毕后它的结果返回原始的CompletableFuture的计算结果或者返回异常
微服务实战
我们现在springcloud 微服务项目都用到这种模式CompletableFuture异步获取运行结果
在这里插入图片描述
一个请求完整实列
在这里插入图片描述
在这里插入图片描述

在这里插入图片描述

  • 0
    点赞
  • 3
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值