Java 异步编程

Wesley13
• 阅读 716

  昨天头儿给的学习文档我还没看完,头儿说:“MongoDB光会简单的添删改查什么的不行,要深入了解,你们连$set和$inc使用场景都分不清。”

  确实,学习过一年多SQL,确实对学习MongoDB有点影响。

  不过,今天数据库的事情先翻过去,因为我在学习文档中还看到了另外一个加大加粗的标题——异步编程

  Java在Java8之前貌似(因为我也刚学,所以不对还请各位前辈指正)没有真正实现异步编程的方法,当时异步编程会使用回调或者使用其他的框架(如Netty和Guava)来实现。后来Java8借鉴了很多框架的思想,可以借助JDK原生的CompletableFuture来实现异步操作,而且用Lambda表达式来写匿名内部类大大简化了代码量。

  那么,异步编程到底是用来干什么的呢?

  试想这样的场景——老爸有俩孩子:小红和小明。老爸想喝酒了,他让小红去买酒,小红出去了。然后老爸突然想吸烟了,于是老爸让小明去买烟。在面对对象的思想中,一般会把买东西,然后买回来这件事作为一个方法,如果按照顺序结构或者使用多线程同步的话,小明想去买烟就必须等小红这个买东西的操作进行完。这样无疑增加了时间的开销。异步就是为了解决这样的问题。你可以分别给小红小明下达指令,让他们去买东西,然后你就可以自己做自己的事,等他们买回来的时候接收结果就可以了。

  所以,为了尽快学习异步操作,我使用Java8的方法编写了这样一段代码来帮助了解:

 1 package com.liumaowu;
 2 
 3 import java.util.concurrent.CompletableFuture;
 4 import java.util.concurrent.ExecutorService;
 5 import java.util.concurrent.Executors;
 6 
 7 public class TestFuture {
 8     public static void main(String[] args) {
 9         //两个线程的线程池
10         ExecutorService executor= Executors.newFixedThreadPool(2);
11         //小红买酒任务,这里的future2代表的是小红未来发生的操作,返回小红买东西这个操作的结果
12         CompletableFuture<String> future2 = CompletableFuture.supplyAsync(()-> {
13             System.out.println("爸:小红你去买瓶酒!");
14             try {
15                 System.out.println("小红出去买酒了,女孩子跑的比较慢,估计5s后才会回来...");
16                 Thread.sleep(5000);
17                 return "我买回来了!";
18             } catch (InterruptedException e) {
19                 System.err.println("小红路上遭遇了不测");
20                 return "来世再见!";
21             }
22         },executor);
23 
24         //小明买烟任务,这里的future1代表的是小明未来买东西会发生的事,返回值是小明买东西的结果
25         CompletableFuture<String> future1 = CompletableFuture.supplyAsync(()->{
26             System.out.println("爸:小明你去买包烟!");
27             try {
28                 System.out.println("小明出去买烟了,可能要3s后回来...");
29                 Thread.sleep(3000);
30                 return "我买回来了!";
31             } catch (InterruptedException e) {
32                 System.out.println("小明路上遭遇了不测!");
33                 return "这是我托人带来的口信,我已经不在了。";
34             }
35         },executor);
36 
37         //获取小红买酒结果,从小红的操作中获取结果,把结果打印
38         future2.thenAccept((e)->{System.out.println("小红说:"+e);});
39         //获取小明买烟的结果
40         future1.thenAccept((e)->{System.out.println("小明说:"+e);});
41 
42         System.out.println("爸:loading......");
43         System.out.println("爸:我觉得无聊甚至去了趟厕所。");
44         System.out.println("爸:loading......");
45     }
46 }

  这个运行结果如下:

爸:小红你去买瓶酒!
小红出去买酒了,女孩子跑的比较慢,估计5s后才会回来...
爸:小明你去买包烟!
小明出去买烟了,可能要3s后回来...
爸:loading......
爸:我觉得无聊甚至去了趟厕所。
爸:loading......
小明说:我买回来了!
小红说:我买回来了!

  因为sleep时间调的挺大,所以可以很明显的看到小明买回来的结果是在等待之后一会儿才跳出来,小红买回来的结果也等待了一会儿才跳出来。因为是先让小红买,再让小明出去的,但是小明的结果先回来,这说明什么时候取到结果取决于操作的时间长度。

  之后我把取futrue的结果的操作放到了老爸等待语句的下面,如下:

 1 /*
 2 上面的代码不动
 3 */
 4         System.out.println("爸:loading......");
 5         System.out.println("爸:我觉得无聊甚至去了趟厕所。");
 6         System.out.println("爸:loading......");
 7         //获取小红买酒结果
 8         future2.thenAccept((e)->{System.out.println("小红说:"+e);});
 9         //获取小明买烟的结果
10         future1.thenAccept((e)->{System.out.println("小明说:"+e);});

  多次运行之后结果就比较有意思了:

结果1:Java 异步编程

结果2:Java 异步编程

结果3Java 异步编程

  这种解决异步的方式还是使用到了多线程,在获取结果之前,操作的顺序取决于线程操作到了哪一步,比如结果2,因为小红线程启动的慢了,所以小明先出去了。但是如果先取结果的话,会确保这个线程已经启动了,所以老爸loading始终显示在老爸发出买东西命令之后。这也算先强制线程启动,再进行主操作。

  (补充:可能因为更换了电脑,性能有所提高,导致再次试验这段代码的时候只出现结果一。但是爸爸的loading代码出现在小明执行动作的前面已经可以解释,这段异步代码的执行时间取决于线程的启动速度和执行。)

在看了异步之后,不可避免地会把同步/异步/多线程弄混淆,那么我们再来总结下几个东西的区别

一般情况:顺序结构,必须等待前面的操作完成(两个人说话,a把所有话说完,b才能继续说)

并发:同一时间段处理多个任务的能力(两人说话,支持你一言我一语的交流,两人在一个时间段内都有说话,是基于时间段内的同时发生)

并发又有同步和互斥

互斥:不能同时使用临界资源(有一个共享资源--话筒,两人必须用话筒说话,但同时只能有一个人用这个话筒,保证了只有一个人在说话)

   同步:前一个处理的结果作为下一个处理的资源。大多数情况下,同步已经实现了互斥。(两人你一言我一语的交流,我必须知道你说了啥我才能接上你的话)

并行:同一时刻处理多个任务的能力(两人合唱,同时出声)

异步:不用等待一个结果出来,可以继续其他操作(两个人不说话了,寄信,a把信拿到邮局就不用管了,回家可以想干嘛就干嘛,等b回信到了,取邮局接收一下结果--b的回信就可以了)

多线程:如果说同步和异步是对如何处理事情的要求,那么多线程就是实现这些要求的方法

点赞
收藏
评论区
推荐文章
待兔 待兔
5个月前
手写Java HashMap源码
HashMap的使用教程HashMap的使用教程HashMap的使用教程HashMap的使用教程HashMap的使用教程22
待兔 待兔
4年前
Dart | 浅析dart中库的导入与拆分
前言最近十分热门的跨平台框架使用了一门比较生僻的编程语言dart。dart语言本身深受早期一些编程语言的影响。特别是Smalltalk,Java和JavaScript。我是从Java语言向dart过度的,一开始感觉很不错,快速就对这门语言有了一个初步的认识,并能够写小段代码了。但在flutter的不断学习过程中,我遇到了不少因为dart的一些语
Wesley13 Wesley13
3年前
java架构师之路:推荐的15本书
一对于没有Java编程经验的程序员要入门,随便读什么入门书籍都一样,这个阶段需要你快速的掌握Java基础语法和基本用法,宗旨就是“囫囵吞枣不求甚解”,先对Java熟悉起来再说。用很短的时间快速过一遍Java语法,连懵带猜多写写代码,要“知其然”。在有了一定的Java编程经验之后,你需要“知其所以然”了。这个时候《Java编程
Wesley13 Wesley13
3年前
java从程序员走向架构师
作为Java程序员来说,最痛苦的事情莫过于可以选择的范围太广,可以读的书太多,往往容易无所适从。我想就我自己读过的技术书籍中挑选出来一些,按照学习的先后顺序,推荐给大家,特别是那些想不断提高自己技术水平的Java程序员们。一、Java编程入门类对于没有Java编程经验的程序员要入门,随便读什么入门书籍都一样,这个阶段需要你快速的掌握Java基础语法和
Wesley13 Wesley13
3年前
MongoDB学习(1)
不管我们学习什么数据库都应该学习其中的基础概念,在mongodb中基本的概念是文档、集合、数据库,下面我们挨个介绍。数据库一个mongodb中可以建立多个数据库,MongoDB中默认数据库为"db",该数据库存储在data目录中。在MongoDB中可以创建数据库,如果你想使用MongoDB,创建数据库不是必要的。"showd
Wesley13 Wesley13
3年前
Java数据结构之单向链表,兼谈对象引用
昨天参加中兴笔试,被一个单项链表的编程题给弄崩了。于是这几天开始学习Java与数据结构之间的知识。上过数据结构的课程,当时使用C演示的,导致了我一直觉得Java和数据结构之间的关系不是很大。直到今天,看了《Java数据结构与算法》,才如梦方醒。恩,要好好学习。下面贴一下我的代码:packagedatastructure;/
Wesley13 Wesley13
3年前
MongoDB学习(1)
知识点:  1MongoDB安装,启动和卸载  2基本概念  3基本的增删改查操作(CURD)   来回顾总结一把学习的mongodb,如果有javascript基础,学习"芒果DB"还是很好理解的,如果会使用mysql,那就更容易了。  mongodb是一个介于nosql数据库和mysql数
Stella981 Stella981
3年前
JVM垃圾收集算法之清除算法
  最近看了一些大佬的博文,文中提到说:学习知识不能一味的死学滥学,在学之前要明白为什么要学这个知识,在实际的应用中怎么运用这个知识。我觉得说的很对,很多时候我学习确实是了解了这是什么原理,但是要说到实际中怎么应用确实比较难总结。但以后我也会尽量总结这个知识点有什么用。  看前总结:为什么要了解垃圾回收中清除算法的具体实现,那是因为在jvm有很多
一文带你读懂设计模式之责任链模式 | 京东云技术团队
翻了一下之前刚入职时候的学习笔记,发现之前在熟悉业务代码的时候曾经专门学习并整理过过设计模式中的责任链模式,之前只是对其简单了解过常用的设计模式有哪些,并未结合实例和源码深入对其探究,利用熟悉代码契机进行系统学习并整理文档如下。