如果你不读它,你就不知道。据说在JDK7升级到JDK8的时候,升级了很多内容。不得不说,这次升级真的很大。什么是异步编程?很多时候,我们在进程中使用单线程从头到尾执行程序。例如,程序向另一台服务器发送请求。由于网络等外部原因,此类通信任务往往会消耗大量时间。如果进程在这段时间内简单地等待网络或网络上其他机器的响应,将会严重降低性能。如果一个程序调用一个方法并在继续之前等待它执行完整的处理,则称该程序是同步的。反之,在处理完成之前返回到调用方法是异步的。我们在编程语言的过程中加入了一部分异步控制,这部分编程可以称为异步编程。JDK中异步编程的FutureFuture模式在JDK5中就有了。Future模式只是发起一个耗时操作,函数立即返回。具体操作的实际执行是由另一个工作线程完成的,不会阻塞客户端线程。因此,当工作线程执行耗时操作时,客户端不需要等待,可以继续做其他事情,需要的时候再从工作线程中获取结果。举个最简单的例子,当我们烧开水的时候,不需要一直盯着炉子看。在烧开水的过程中,我们需要做一些其他的事情,比如一会儿写代码,但是当你写代码之前,它会给你一个错误的结果,比如我已经烧开了,但是当你在写代码,他会开始疯狂加火,等到水烧开,等到你口渴了想倒水的时候,发现水已经烧开了,也就是说,你收到一个错误的结果,然后再写代码。事实上,Future模式并不能立即给你想要的结果,但是它会给你一个契约,你可以随时使用这个契约得到你想要的结果。异步模式主要是与同步模式进行比较。我们画个图看看。黄色区域位置的Y轴长度表示需要等待的全部时间。这段时间,你什么也做不了,只能在这里等着,但是如果是异步的,根本不需要这样。Future模式在JDK中有一套完整的实现。下面写个案例代码实验:没有使用Future的代码。NormalThreadTest公共类NormalThreadTest{publicstaticvoidmain(String[]args)throwsException{longstart=System.currentTimeMillis();//启动厨具购买线程ShoppingThreadshopping=newShoppingThread();购物开始();购物.join();//保证厨具购买和交付//获取和购买厨具KitchenWarekc=shopping.kc;//购买原料FoodMaterialfm=newFoodMaterial();线程.睡眠(2000);System.out.println("第2步:配料到位");//烹饪食物cooking(kc,fm);System.out.println("第三步:食物烹饪完成");长端=System.currentTimeMillis();系统输出。println("烹饪时间是:"+(end-start));}/***定义网购厨具线程*@authorAdministrator**/staticclassShoppingThreadextendsThread{//厨具对象引用privateKitchenWarekc;@Overridepublicvoidrun(){System.out.println("第一步:在线下单");System.out.println("第一步:等待厨具");尝试{Thread.sleep(5000);//等待厨具时间}catch(InterruptedExceptione){e.printStackTrace();}System.out.println("第一步:快递");//生产厨具kc=newKitchenWare();}}/***厨具类*@authorAdministrator**/staticclassKitchenWare{}/***食材类*@authorAdministrator**/staticclassFoodMaterial{}/***定义食物的烹饪方法*@paramkc*@paramfm*/staticvoidcooking(KitchenWarekc,FoodMaterialfm){}}运行结果:Step1:在线订购Step1:等待厨具Step1:快递Step1Step2:食材已经到位第3步:美食烹饪完成烹饪时间为:7043Future的代码已被使用FutureThreadTest公共类FutureThreadTest{publicstaticvoidmain(String[]args)throwsException{longstart=System.当前时间毫秒();Callablecallable=newCallable(){publicKitchenWarecall()throwsException{System.out.println("第一步:在线下单");System.out.println("第一步:等待厨具");尝试{Thread.sleep(5000);//等待厨具时间}catch(InterruptedExceptione){e.printStackTrace();}System.out.println("第一步:快递");返回新的厨具();}};//封装为异步执行对象FutureTasktask=newFutureTask<>(callable);新线程(任务).start();//购买原料FoodMaterialfm=newFoodMaterial();线程.睡眠(2000);System.out.println("第2步:配料到位");如果(!task.isDone()){System.out.println("厨具还没到....");}//通过阻塞KitchenWare获取异步块执行的结果kc=task.get();//阻塞//烹饪美食cooking(kc,fm);System.out.println("第三步:美食烹饪完成");长端=System.currentTimeMillis();System.out.println("烹饪时间为:"+(end-start));}/***Kitchenware*@authorAdministrator**/staticclassKitchenWare{}/***Ingredients*@authorAdministrator**/staticclassFoodMaterial{}/***定义食物的烹饪方法*@paramkc*@paramfm*/staticvoidcooking(KitchenWarekc,FoodMaterialfm){}}执行结果:Step1:网上下单Step1:等待厨具Step2:食材到位Notyet...Step1:快递第三步:食物烹饪完成。cooking时间为:5027这个是JDK5中的Future实现异步编程的,那么我们来看异步1.8编程CompletableFutureFuture可以实现获取异步执行结果的需求,但是没有提供通知机制。我们无法知道Future什么时候完成,通过上面的代码我们完全可以看到。为什么在JDK5之后引入了新的异步编程,因为使用Future或者阻塞,在future.get()的地方等待Future返回的结果,然后又变成了同步操作。要么使用isDone()轮询判断Future是否完成,会消耗CPU资源。所以阿芬猜测CompletableFuture是在JDK8推出的。以前,Future需要等待isDone为真才能知道任务已完成。或者用get方法调用的时候会阻塞。CompletableFuture的使用可以使用then、when等操作来防止上面的阻塞和pollingisDone现象。CompletableFuture有四种创建CompletableFuture对象的方法。publicstaticCompletableFuturerunAsync(Runnablerunnable)publicstaticCompletableFuturerunAsync(Runnablerunnable,Executorexecutor)publicstaticCompletableFuturesupplyAsync(Supplier供应商)publicstaticCompletableFuturesupplyAsync(Suppliersupplier,Executorexecutor)Asyncc是异步的意思,supplyAsync与runAsync的区别在于它与前者异步返回一个结果,而后者为void。第二个函数的第二个参数表示是我们自己创建的线程Pool,否则使用默认的ForkJoinPool.commonPool()作为它的线程池。其中Supplier是一个函数式接口,也就是说它是一个生成器,传入0个参数,返回一个结果。我们写最简单的测试代码:publicstaticvoidtest2()throwsException{//supplyAsync内部使用ForkJoinPool线程池执行任务CompletableFuturecompletableFuture=CompletableFuture.supplyAsync(()->{//模拟耗时任务System.out.println("taskdoing...");try{Thread.sleep(3000);}catch(InterruptedExceptione){e.printStackTrace();}//返回结果return"100";}).whenComplete((v,r)->{System.out.println("计算结果为:"+v);});//CompletableFuture中使用的线程池中的线程默认是daemon。主线程结束后,整个程序//结束,任务中的代码只有在加入主线程后才能执行。Thread.currentThread().join();使用CompletableFuture可以有效避免使用Future缺点的发生。好像JDK的每一次更新不仅增加了一些新的内容,而且像开发一样,每一次迭代也会更新一些以前不完善的内容,不是吗?