前言异步编程是一种让程序并发运行的手段。它允许同时发生多件事。当程序调用一个需要长时间运行的方法时,不会阻塞当前的执行流程,程序可以继续运行。当方法执行完成后,会根据需要通知主线程获取其执行结果或失败。异常的原因。使用异步编程可以大大提高我们程序的吞吐量,更好的面对更高并发的场景和更好的利用已有的系统资源,也在一定程度上减少了用户的等待时间。在这篇文章中,让我们看看在Java语言中使用异步编程的方法。在Java语言中使用异步编程最简单的方法就是创建一个Thread来实现它。如果你使用的JDK版本是8以上,可以使用Lambda表达式来更简洁。为了更好的体现异步的效率,下面给出一个同步版本和异步版本的例子作为对比:/***@authormghio*@since2021-08-01*/publicclassSyncWithAsyncDemo{publicstaticvoiddoOneThing(){尝试{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(秒表);}privatestaticvoidtestAsynchronize()throwsInterruptedException{System.out.println("--------------------testAsynchronize-------------------");//创建一个线程执行doOneThingThreaddoOneThingThread=newThread(SyncWithAsyncDemo::doOneThing,"doOneThing-Thread");doOneThingThread.start();doOtherThing();//等待doOneThing线程完成doOneThingThread.join();}privatestaticvoidtestSynchronize(){System.out.println("--------------------testSynchronize------------------");doOneThing();doOtherThing();}}同步执行的操作如下:注释掉同步的代码调用版本,并得到异步执行的结果如下:从两次运行结果可以看出,同步版本耗时4002ms,异步版本耗时2064ms,异步执行时间减少了近一半。可以看出使用异步编程后程序运行时间可以大大缩短,示例异步线程代码在main方法中开启一个线程doOneThing-Thread异步执行doOneThing任务。此时线程与main主线程并发运行,即任务doOneThing和任务doOtherThing并发运行,等待主线程运行完doOtherThing任务后,等待线程doOneThing同步运行完毕.整体比较简单。但是这个例子只能作为例子。如您使用生产环境发生意外,后果自负。使用上面的Thread方法进行异步编程有两个明显的问题。.Creating线程不被重用。我们知道,频繁的线程创建和销毁需要一定的开销,示例中没有限制线程数。如果使用不当,可能会导致系统线程耗尽,从而引发事故。这个问题使用线程池就可以解决问题。异步任务无法获取最终的执行结果。示例中的这种方法是不够的。这时候就需要用到下面介绍的第二种FutureTask方法。FutureTask方法从JDK1.5开始引入了Future接口和实现Future接口的FutureTask类来表示异步计算结果。这个FutureTask类不仅实现了Future接口,还实现了Runnable接口,代表一个可以产生结果的Runnable。它可以处于这三种状态:创建FutureTask时未启动、在执行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执行操作产生结果。代码如下:/***@authormghio*@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();}返回参数+""+"doOtherThing";});}publicstaticvoidmain(String[]args)throwsExecutionException,InterruptedException{StopWatchstopWatch=newStopWatch("CompletableFutureDemo");stopWatch.start();//异步执行版本testCompletableFuture();stopWatch.stop();System.out.println(秒表);}privatestaticvoidtestCompletableFuture()throwsInterruptedException,ExecutionException{//先执行doOneThing任务,再执行doOtherThing任务CompletableFutureresultFuture=doOneThing().thenCompose(CompletableFutureDemo::doOtherThing);//获取任务结果StringdoOneThingResult=resultFuture.get();//获取执行结果System.out.println("DoOneThingandDoOtherThingexecutefinished.result="+doOneThingResult);}}执行结果如下:在主线程main中,首先调用方法doOneThing()启动一个异步任务,并返回对应的CompletableFuture对象,我们将其命名为doOneThingFuture,然后使用CompletableFuture的thenCompose()方法on在doOneThingFuture的基础上,让doOneThingFuture方法执行,将其执行结果作为doOtherThing(Stringparameter)方法的参数来创建我们不需要显式使用ExecutorService来返回异步任务。CompletableFuture内部使用Fork/Join框架来异步处理任务。因此,它使得我们编写的异步代码更加简洁。此外,CompletableFuture类非常强大,提供了很多方便的方法。有关CompletableFuture的更多使用信息,请参阅本文。小结本文介绍了在Java中使用JDK异步编程的三种方式。这些是我们异步编程最基本的工具。在其之上的是Guava库提供的ListenableFuture和Futures类,以及Spring框架提供的异步类。执行能力,使用@Async等注解实现异步处理,有兴趣的可以自行学习。