美团外面,滴滴打车很多场景都会使用到。
当我们在软件下单的时候, 付款之后,系统马上就会提示我们下单成功,而
而这个背后我们来分析下,有很多地方有数据处理的工作。保存订单到数据库、通知商家接单、通知骑手取货。整个流程的体验是非常快的,这其中肯定也是异步化的。
我们后端的开发也是一样的,我们不能因为某一次的延迟而让后面所以的请求进行等待。
异步技术:
Java 5 Future接口
使用Future获得异步执行结果时,要么调用阻塞方法get(),要么轮询看isDone()是否为true,这两种方法都不是很好,因为主线程也会被迫等待。
public class TestK { public static int helloZero() throws ExecutionException, InterruptedException { ExecutorService executorService = Executors.newFixedThreadPool(2); Future<Integer> result = executorService.submit(()->{ TimeUnit.SECONDS.sleep(5); return 100; }); System.out.println(result.get()); return 1; } public static int helloOne() throws ExecutionException, InterruptedException { ExecutorService executorService = Executors.newFixedThreadPool(2); Future<Integer> result = executorService.submit(()->{ return 300; }); while (!result.isDone()) { TimeUnit.MILLISECONDS.sleep(100); } System.out.println(result.get()); return 3; } public static void main(String[] args) throws ExecutionException, InterruptedException { TestK.helloZero(); TestK.helloOne(); } }
输出结果
通过主线程输出语句,我们看到必须要等待线程池执行完成才会执行main线程。这样的话非常浪费cpu资源的,为什么不能用类似观察者或者监听的模式,当任务完成之后,我就能收到结果。这就要涉及到回调函数。
1、同步阻塞调用
即串行调用,响应时间为所有服务的响应时间总和;
2、半异步(异步Future)
线程池,异步Future
使用场景:并发请求多服务。总耗时为最长响应时间;提升总响应时间,但是阻塞主请求线程,高并发时依然会造成线程数过多,CPU上下文切换;
3、全异步(Callback)
Callback方式调用,使用场景:不考虑回调时间且只能对结果做简单处理,如果依赖服务是两个或两个以上服务,则不能合并两个服务的处理结果;不阻塞主请求线程,但使用场景有限。
4、异步回调
异步回调链式编排(JDK8 CompletableFuture),使用场景:其实不是异步调用方式,只是对依赖多服务的Callback调用结果处理做结果编排,来弥补Callback的不足,从而实现全异步链式调用。
CompletableFuture类介绍:
* @author Doug Lea * @since 1.8 */ public class CompletableFuture<T> implements Future<T>,CompletionStage<T> {}
列子1:那个线程跑的快用哪个acceptEither函数
public class TestU { public static CompletableFuture<Integer> m1() { return CompletableFuture.supplyAsync(() -> { try { TimeUnit.SECONDS.sleep(2); } catch (InterruptedException e) { e.printStackTrace(); } return 1111; }); } private static CompletableFuture<Integer> m2() { return CompletableFuture.supplyAsync(() -> { try { TimeUnit.SECONDS.sleep(1); } catch (InterruptedException e) { e.printStackTrace(); } return 2222; }); } /*** * acceptEither函数 * 那个线程跑的快用哪个 * @param args * @throws Exception */ public static void main(String[] args) throws Exception { m1().acceptEither(m2(), t -> { System.out.println("t = " + t); }).get(); } }
输出结果为
列子2:两个任何结果合并:thenCombine函数
public class TestJ { public static void main(String[] args) { try { String k = CompletableFuture.supplyAsync(() -> 1).thenCombine(CompletableFuture.supplyAsync(() -> "2"), (a, b) -> { System.out.println("a = " + a); System.out.println("b = " + b); return a + b; }).get(); System.out.println("k = " + k); } catch (InterruptedException e) { e.printStackTrace(); } catch (Exception e) { e.printStackTrace(); } } }
输出结果为
场景:
supplyAsync thenApplyAsync
ABC C必须等到A条件完成了才完成,而B不需要等待,这种如何处理?
场景介绍:
1、获取sku的基本信息 1S
2、获取sku的图片信息 2s
3、获取sku的促销信息 3s
4、规格信息spu
5、............
public class TestN { public static void main(String[]args) throws Exception { // 第一个任务:商品id CompletableFuture<String> cfQuery = CompletableFuture.supplyAsync(()->{ return query("iphone12"); }); // // query成功后继续执行下一个任务: CompletableFuture<String> cfFetch = cfQuery.thenApplyAsync((code)->{ return comment(code); }); cfFetch.thenAccept((result)->{ System.out.println(result); }); // // 主线程不要立刻结束,否则CompletableFuture默认使用的线程池会立刻关闭: Thread.sleep(2000); } private static String query(String name) { try{ Thread.sleep(100); }catch (Exception e){ e.printStackTrace(); } int random = new Random().nextInt(100); System.out.println("random = "+random); return random <= 20 ? "20210709":"0000"; } private static String comment(String code){ if(code.equals("0000")){ return "没有任何评论"; } return "苹果没有小米好"; }
输出结果为