java 异步编程

前言在 JAVA 中你不了解异步编程,crud 完全没有问题,但是有的需求你无法优雅的实现 。
js 也存在异步编程,当你理解了用同步的思维编写异步的代码时,相信你在编程上的造诣又更进一步 。
大多人都在追捧微服务,可能他们只会用 Ribbon 和 Feign 。微服务是一个架构上的选择,当你没有达到架构层次时,我认为你应该更加注重业务上的代码编写,即微服务中单体服务代码的编写 。
单体服务性能极差,你的微服务整体性能也好不到哪里去,只能通过限流、熔断外加多部署机器来解决并发低的问题 。在你想玩微服务之前,并发玩好了再考虑高并发 。先把 java 中 juc 包下的并发相关的知识整的明明白白再进行下一步,这花不了几个时间 。微服务是你进阶之后再学的 。
本来打算继续写 MySQL,但实在提不起来我的兴致(还需要看书研究,毕竟是个黑盒研究),只好拿这篇完成任务了 。
本文内容

  • js 中 Promise 和 async await 的一个列子
  • SpringBoot 中异步编程
  • Future
  • CompletableFuture
js 异步编程要习惯使用 Promise,避免把 fn 当成参数传递,避免回调地狱 。这不仅仅是 api 调用的问题,这是你编程思想转变 。
const awaitFunc = function _awaitFunc() {return Promise.resolve('awaitFunc').then(data =https://www.isolves.com/it/cxkf/yy/JAVA/2020-11-09/> {console.log(data);return 'awaitFunc-then-return-data';});};const async = async function _async() {setTimeout(() => {console.log('验证加入了宏任务队列---1');}, 0);// 加不加 await 有什么区别?await awaitFunc().then(data => {console.log(data);setTimeout(() => {console.log('验证加入了宏任务队列---2');}, 0);});console.log('awaitFunc 执行完在打印');};async();SpringBoot 中异步编程在 SpringBoot @EnableAsync 和 @Async 就可以助你异步编程 。底层原理就是 ThreadPoolExecutor 和 Future 的封装 。
java 异步编程

文章插图
我们拿这个烧水举例子,当你同步串行执行,需要消耗 20 分钟 。同步编程思维模型较简单,容易实现 。
当你多线程异步执行,只需要消耗 16 分钟 。异步编程思维模型稍微复杂一点,多线程之间通信异步转同步是一个挑战 。
@GetMApping("/tea/async")public RetUtil makeTeaAsync() throws InterruptedException, ExecutionException {// Stopwatch 用于计算代码执行时间final Stopwatch started = Stopwatch.createStarted();final Future asyncResult = makeTeaService.boilWater();final Future asyncResult1 = makeTeaService.washTeaCup();asyncResult.get();asyncResult1.get();final long elapsed = started.elapsed(TimeUnit.SECONDS);String str = StrUtil.format("任务执行了 {} 秒", elapsed);final MakeTeaVO makeTeaVO = new MakeTeaVO();makeTeaVO.setMessage(str);return RetUtil.success(makeTeaVO);}@Servicepublic class IMakeTeaServiceImpl implements IMakeTeaService {@Override@Asyncpublic AsyncResult<String> boilWater() throws InterruptedException {System.out.println("洗水壶");TimeUnit.SECONDS.sleep(1);System.out.println("烧开水");TimeUnit.SECONDS.sleep(15);return new AsyncResult("洗水壶->烧开水");}@Override@Asyncpublic AsyncResult<String> washTeaCup() throws InterruptedException {System.out.println("洗茶杯");System.out.println("洗茶壶");System.out.println("拿茶叶");TimeUnit.SECONDS.sleep(4);return new AsyncResult("洗茶杯,洗茶壶,拿茶叶");}}AsyncResult 是 Future 的实现类,当调用 Future.get 会阻塞等待结果的返回 。@Async 也可以指定在那个线程池中执行任务 。
final Future asyncResult = makeTeaService.boilWater();final Future asyncResult1 = makeTeaService.washTeaCup();asyncResult.get();asyncResult1.get();这个 Demo 的实现,需要调用两次 Furute.get() 算是个不优雅的实现 。
@Overridepublic String makeTea() throws InterruptedException {final CountDownLatch count = new CountDownLatch(2);THREAD_POOL_EXECUTOR.execute(() -> {System.out.println("洗水壶");System.out.println("烧开水");try {TimeUnit.SECONDS.sleep(16);} catch (InterruptedException e) {e.printStackTrace();} finally {count.countDown();}});THREAD_POOL_EXECUTOR.execute(() -> {System.out.println("洗茶杯");System.out.println("洗茶壶");System.out.println("拿茶叶");try {TimeUnit.SECONDS.sleep(4);} catch (InterruptedException e) {e.printStackTrace();} finally {count.countDown();}});count.await();System.out.println("泡茶");return "";}@GetMapping("/tea/async2")public RetUtil makeTeaAsync2() throws InterruptedException, ExecutionException {final Stopwatch started = Stopwatch.createStarted();makeTeaService.makeTea();final long elapsed = started.elapsed(TimeUnit.SECONDS);String str = StrUtil.format("任务执行了 {} 秒", elapsed);final MakeTeaVO makeTeaVO = new MakeTeaVO();makeTeaVO.setMessage(str);return RetUtil.success(makeTeaVO);}


推荐阅读