异步编程是一种让程序并发运行的手段。它允许同时发生多件事。当程序调用一个需要长时间运行的方法时,不会阻塞当前的执行流程,程序可以继续运行。当方法执行完成后,会根据需要通知主线程获取其执行结果或失败。异常的原因。使用异步编程可以大大提高我们程序的吞吐量,更好的面对更高并发的场景和更好的利用已有的系统资源,也在一定程度上减少了用户的等待时间。在这篇文章中,让我们看看在Java语言中使用异步编程的方法。在Java语言中实现异步编程最简单的方法是创建一个线程。如果你使用的JDK版本是8以上,可以使用Lambda表达式来更简洁。为了更好的体现异步的效率,下面给出同步版本和异步版本的例子进行对比:/***@authorghio*@since2021-08-01*/publicclassSyncWithAsyncDemo{publicstaticvoiddoOneThing(){try{Thread.sleep(2000);}catch(InterruptedExceptione){e.printStackTrace();}System.out.println("doOneThing---->>>成功");}publicstaticvoiddoOtherThing(){try{Thread.sleep(2000);}catch(InterruptedExceptione){e.printStackTrace();}System.out.println("doOtherThing---->>>成功");}publicsynchronizedstaticvoidmain(String[]args)throwsInterruptedException{StopWatchstopWatch=newStopWatch("SyncWithAsyncDemo");stopWatch.start();//同步调用版本//testSynchronize();//异步调用版本testAsynchronize();stopWatch.stop();System.out.println(stopWatch);}privatestaticvoidtestAsynchronize()throwsInterruptedException{系统。out.println("--------------------testAsynchronize----------------");//创建线程执行doOneThingThreaddoOneThingThread=newThread(SyncWithAsyncDemo::doOneThing,"doOneThing-Thread");do??OneThingThread.start();doOtherThing();//等待doOneThing线程完成doOneThingThread.join();}privatestaticvoidtestSynchronize(){System.out.println("-------------------testSynchronize--------------------");doOneThing();doOtherThing();}}同步执行作为如下:注意替换掉同步调用版本的代码后,异步执行的结果如下:从两次运行的结果可以看出,同步版本耗时4002ms,异步版本耗时2064ms,而异步执行时间减少了近一半。可以看出使用异步编程可以大大缩短doOneThing和任务doOtherThing并发运行的程序运行时间,然后在主线程运行完doOtherThing任务后同步等待线程doOneThing运行完毕,整体上比较简单。但是这个例子只能作为例子。如果您在生产环境中使用,出现事故后果由您自行承担。使用上面的Thread方法进行异步编程有两个明显的问题。FutureTaskFutureTask方法从JDK1.5开始引入了Future接口和实现Future接口的FutureTask类来表示异步计算结果。这个FutureTask类不仅实现了Future接口,还实现了Runnable接口,代表一个可以产生结果的Runnable。它可以处于这三种状态:未启动当创建了一个FutureTask并且没有执行FutureTask.run()方法时,在执行FutureTask.run()方法之前,在执行FutureTask.run()方法。FutureTask.run()方法作为结果正常执行或者调用FutureTask.cancel(booleanmayInterruptIfRunning)方法实现,FutureTask类实现了Future接口打开和取消任务的方法,查询任务是否是FutureTask.run()方法调用异常结束后获取计算结果。要获取FutureTask任务的结果,我们只能通过调用getXXX()系列方法来获取。这些方法在结果还没有出来的时候就会被封杀。同时任务可以是Callable类型(有返回结果)或者Runnable类型(不返回结果)。我们修改上面的例子,将两个任务方法修改为返回String类型。FutureTask的使用方法如下:privatestaticvoidtestFutureTask()throwsExecutionException,InterruptedException{System.out.println("-----------------testFutureTask------------------");//创建一个FutureTask(doOneThing任务)FutureTaskfutureTask=newFutureTask<>(FutureTaskDemo::doOneThing);//使用线程池执行doOneThing任务ForkJoinPool.commonPool().execute(futureTask);//执行doOtherThing任务StringdoOtherThingResult=doOtherThing();//同步等待线程执行doOneThing任务结束StringdoOneThingResult=futureTask.get();//任务执行结果输出System.out.println("doOneThingResult---->>>"+doOneThingResult);System.out.println("doOtherThingResult---->>>"+doOtherThingResult);}使用FutureTask异步的耗时编程方法与上面的Thread方法类似。它的本质是另开一个线程去做doOneThing任务,然后等待返回。运行结果如下:本例中doOneThing和doOtherThing都是有返回值的任务(都是返回String类型的结果),我们在主线程main中创建一个异步任务FutureTask来执行doOneThing,然后使用ForkJoinPool.commonPool()创建一个线程池(这里看ForkJoinPool的介绍),然后调用线程池的execute方法提交futureTask去线程池执行。从例子中可以看出,虽然FutureTask提供了一些方法让我们获取任务的执行结果,任务是否完成等,但是使用起来还是比较复杂的。在一些比较复杂的场景下(比如多个FutureTasks之间的关系表示)编码还是比较繁琐的,或者当我们调用getXXX()系列方法时,调用线程在任务执行之前还是会被阻塞,而效果无法实现异步编程。基于这些问题,在JDK8中引入了CompletableFuture类,我们来看看如何使用CompletableFuture来实现异步编程。CompletableFuture方法JDK8引入了CompletableFuture类,它实现了Future和CompletionStage接口,并提供了一系列用于异步编程的方法,如supplyAsync、runAsync、thenApplyAsync。此外,CompletableFuture还有一个重要的功能,就是让两个或多个CompletableFutures执行操作产生结果。代码如下:/***@authorghio*@since2021-08-01*/publicclassCompletableFutureDemo{publicstaticCompletableFuturedoOneThing(){returnCompletableFuture.supplyAsync(()->{try{Thread.sleep(2000);}catch(InterruptedExceptione){e.printStackTrace();}return"doOneThing";});}publicstaticCompletableFuturedoOtherThing(Stringparameter){returnCompletableFuture.supplyAsync(()->{try{Thread.sleep(2000);}catch(InterruptedExceptione){e.printStackTrace();}returnparameter+""+"doOtherThing";});}publicstaticvoidmain(String[]args)throwsExecutionException,InterruptedException{StopWatchstopWatch=newStopWatch("CompletableFutureDemo");stopWatch.start();//异步执行VersiontestCompletableFuture();stopWatch.stop();System.out.println(stopWatch);}privatestaticvoidtestCompletableFuture()throwsInterruptedException,ExecutionException{//先执行doOneThing任务,再执行doOtherThing任务CompletableFutureresultFuture=doOneThing().thenCompose(CompletableFutureDemo::doOtherThing);//获取任务结果StringdoOneThingResult=resultFuture.get();//获取执行结果System.out.println("DoOneThingandDoOtherThingexecutefinished.result="+doOneThingResult);}}执行结果为如下:在main线程main中,首先调用方法doOneThing()方法启动一个异步任务,并返回对应的CompletableFuture对象,我们将其命名为doOneThingFuture,然后在此基础上使用CompletableFuture的thenCompose()方法doOneThingFuture让doOneThingFuture方法执行最后,将其执行结果作为doOtherThing(Stringparameter)方法的参数创建的异步任务返回。我们不需要显式使用ExecutorService。CompletableFuture使用Fork/Join框架来异步处理任务。因此,它可以让我们写出异步的代码更加简洁。此外,CompletableFuture类非常强大,提供了很多方便的方法。有关CompletableFuture的更多使用信息,请参阅本文。